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,67 @@ #define LLVM_DEBUGINFO_DWARF_DWARFDEBUGMACRO_H #include "llvm/ADT/SmallVector.h" -#include "llvm/Support/DataExtractor.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.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 + uint32_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; } + void setFlags(uint8_t Flags) { + assert(Flags == 2 && + "Only DWARF32 is supported and debug_line_offset must be present."); + HeaderData.Flags |= + MACRO_FLAG_OFFSET_SIZE_32 | MACRO_FLAG_DEBUG_LINE_OFFSET; + } + void setDebugLineOffset(uint32_t DebugLineOffset) { + HeaderData.DebugLineOffset = DebugLineOffset; + } + /// A single macro entry within a macro list. struct Entry { /// The type of the macro entry. @@ -47,11 +100,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. + void 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,18 @@ } } +static void dumpMacroSection(DWARFContext &Context, raw_ostream &OS, + DWARFDataExtractor MacroData) { + uint64_t Offset = 0; + DWARFDebugMacro Macro; + while (MacroData.isValidOffset(Offset)) { + Macro.parseMacroHeader(MacroData, &Offset); + 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 +455,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 +828,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 +1492,7 @@ DWARFSectionMap PubtypesSection; DWARFSectionMap GnuPubnamesSection; DWARFSectionMap GnuPubtypesSection; + DWARFSectionMap MacroSection; DWARFSectionMap *mapNameToDWARFSection(StringRef Name) { return StringSwitch(Name) @@ -1499,6 +1520,7 @@ .Case("apple_namespaces", &AppleNamespacesSection) .Case("apple_namespac", &AppleNamespacesSection) .Case("apple_objc", &AppleObjCSection) + .Case("debug_macro", &MacroSection) .Default(nullptr); } @@ -1853,6 +1875,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,59 @@ M->emplace_back(); Entry &E = M->back(); // 1. Macinfo type - E.Type = data.getULEB128(&Offset); + E.Type = data.getULEB128(Offset); if (E.Type == 0) { - // Reached end of a ".debug_macinfo" section contribution. - continue; + if (getVersion() >= 5) + return; + else + // 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; } } } + +void DWARFDebugMacro::parseMacroHeader(DWARFDataExtractor data, + uint64_t *Offset) { + setHeaderOffset(Offset); + setVersion(data.getU16(Offset)); + setFlags(data.getU8(Offset)); + setDebugLineOffset(data.getU32(Offset)); +} Index: llvm/test/DebugInfo/X86/debug-macro-v5.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/X86/debug-macro-v5.ll @@ -0,0 +1,81 @@ +; RUN: %llc_dwarf --dwarf-version=5 -O0 -filetype=obj < %s | llvm-dwarfdump -v - | FileCheck %s + +; CHECK-LABEL: .debug_info contents: +; CHECK: DW_AT_macros [DW_FORM_sec_offset] (0x00000000) + +; CHECK-LABEL: .debug_macro contents: +; 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: BAZ 7 +; CHECK-NEXT: DW_MACRO_define_strp - lineno: 5 macro: YEA 8 +; CHECK-NEXT: DW_MACRO_undef_strp - lineno: 14 macro: YEA +; 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__ 10 +; CHECK-NEXT: DW_MACRO_define_strp - lineno: 0 macro: __clang_minor__ 0 + +; ModuleID = 'test.c' +source_filename = "test.c" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" +; Function Attrs: noinline nounwind optnone uwtable +define dso_local i32 @main() #0 !dbg !25 { + %1 = alloca i32, align 4 + %2 = alloca i32, align 4 + call void @llvm.dbg.declare(metadata i32* %1, metadata !29, metadata !DIExpression()), !dbg !30 + store i32 3, i32* %1, align 4, !dbg !30 + call void @llvm.dbg.declare(metadata i32* %2, metadata !31, metadata !DIExpression()), !dbg !32 + store i32 5, i32* %2, align 4, !dbg !32 + ret i32 0, !dbg !33 +} +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +attributes #0 = { noinline nounwind optnone uwtable } +attributes #1 = { nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!21, !22, !23} +!llvm.ident = !{!24} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, macros: !3, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/home/", checksumkind: CSK_MD5, checksum: "ef6a7032e0c7ceeef621583f2c00dc80") +!2 = !{} +!3 = !{!4, !17, !18, !19, !20} +!4 = !DIMacroFile(file: !1, nodes: !5) +!5 = !{!6, !10, !14, !15, !16} +!6 = !DIMacroFile(line: 1, file: !7, nodes: !8) +!7 = !DIFile(filename: "./foo.h", directory: "/home/", checksumkind: CSK_MD5, checksum: "0f0cd0e22b44f49d3944992c8dc28661") +!8 = !{!9} +!9 = !DIMacro(type: DW_MACINFO_define, line: 1, name: "FOO", value: "5") +!10 = !DIMacroFile(line: 2, file: !11, nodes: !12) +!11 = !DIFile(filename: "./bar.h", directory: "/home/", checksumkind: CSK_MD5, checksum: "bf4b34c333eaaa1d7085c25313b8d100") +!12 = !{!13} +!13 = !DIMacro(type: DW_MACINFO_define, line: 1, name: "BAR", value: "6") +!14 = !DIMacro(type: DW_MACINFO_define, line: 4, name: "BAZ", value: "7") +!15 = !DIMacro(type: DW_MACINFO_define, line: 5, name: "YEA", value: "8") +!16 = !DIMacro(type: DW_MACINFO_undef, line: 14, name: "YEA") +!17 = !DIMacro(type: DW_MACINFO_define, name: "__llvm__", value: "1") +!18 = !DIMacro(type: DW_MACINFO_define, name: "__clang__", value: "1") +!19 = !DIMacro(type: DW_MACINFO_define, name: "__clang_major__", value: "10") +!20 = !DIMacro(type: DW_MACINFO_define, name: "__clang_minor__", value: "0") +!21 = !{i32 7, !"Dwarf Version", i32 5} +!22 = !{i32 2, !"Debug Info Version", i32 3} +!23 = !{i32 1, !"wchar_size", i32 4} +!24 = !{!"clang version 10.0.0"} +!25 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 9, type: !26, scopeLine: 9, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!26 = !DISubroutineType(types: !27) +!27 = !{!28} +!28 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!29 = !DILocalVariable(name: "a", scope: !25, file: !1, line: 10, type: !28) +!30 = !DILocation(line: 10, column: 5, scope: !25) +!31 = !DILocalVariable(name: "b", scope: !25, file: !1, line: 11, type: !28) +!32 = !DILocation(line: 11, column: 5, scope: !25) +!33 = !DILocation(line: 12, column: 1, scope: !25)