diff --git a/llvm/lib/CodeGen/AsmPrinter/DIE.cpp b/llvm/lib/CodeGen/AsmPrinter/DIE.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DIE.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DIE.cpp @@ -502,6 +502,8 @@ switch (Form) { case dwarf::DW_FORM_data4: return 4; + case dwarf::DW_FORM_data8: + return 8; case dwarf::DW_FORM_sec_offset: case dwarf::DW_FORM_strp: return AP->getDwarfOffsetByteSize(); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -289,8 +289,8 @@ return DwarfUnit::getHeaderSize() + DWOIdSize; } unsigned getLength() { - return sizeof(uint32_t) + // Length field - getHeaderSize() + getUnitDie().getSize(); + return Asm->getUnitLengthFieldByteSize() + // Length field + getHeaderSize() + getUnitDie().getSize(); } void emitHeader(bool UseOffsets) override; diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -729,6 +729,12 @@ /// Returns the Dwarf Version. uint16_t getDwarfVersion() const; + /// Returns a suitable DWARF form to represent a section offset, i.e. + /// * DW_FORM_sec_offset for DWARF version >= 4; + /// * DW_FORM_data8 for 64-bit DWARFv3; + /// * DW_FORM_data4 for 32-bit DWARFv3 and DWARFv2. + dwarf::Form getDwarfSectionOffsetForm() const; + /// Returns the previous CU that was being updated const DwarfCompileUnit *getPrevCU() const { return PrevCU; } void setPrevCU(const DwarfCompileUnit *PrevCU) { this->PrevCU = PrevCU; } diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -3358,6 +3358,15 @@ return Asm->OutStreamer->getContext().getDwarfVersion(); } +dwarf::Form DwarfDebug::getDwarfSectionOffsetForm() const { + if (Asm->getDwarfVersion() >= 4) + return dwarf::Form::DW_FORM_sec_offset; + assert((!Asm->isDwarf64() || (Asm->getDwarfVersion() == 3)) && + "DWARF64 is not defined prior DWARFv3"); + return Asm->isDwarf64() ? dwarf::Form::DW_FORM_data8 + : dwarf::Form::DW_FORM_data4; +} + const MCSymbol *DwarfDebug::getSectionLabel(const MCSection *S) { return SectionLabels.find(S)->second; } diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfFile.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfFile.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfFile.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfFile.cpp @@ -79,8 +79,8 @@ unsigned DwarfFile::computeSizeAndOffsetsForUnit(DwarfUnit *TheU) { // CU-relative offset is reset to 0 here. - unsigned Offset = sizeof(int32_t) + // Length of Unit Info - TheU->getHeaderSize(); // Unit-specific headers + unsigned Offset = Asm->getUnitLengthFieldByteSize() + // Length of Unit Info + TheU->getHeaderSize(); // Unit-specific headers // The return value here is CU-relative, after laying out // all of the CU DIE. diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -253,9 +253,9 @@ /// Compute the size of a header for this unit, not including the initial /// length field. virtual unsigned getHeaderSize() const { - return sizeof(int16_t) + // DWARF version number - sizeof(int32_t) + // Offset Into Abbrev. Section - sizeof(int8_t) + // Pointer Size (in bytes) + return sizeof(int16_t) + // DWARF version number + Asm->getDwarfOffsetByteSize() + // Offset Into Abbrev. Section + sizeof(int8_t) + // Pointer Size (in bytes) (DD->getDwarfVersion() >= 5 ? sizeof(int8_t) : 0); // DWARF v5 unit type } diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -1695,15 +1695,15 @@ void DwarfUnit::emitCommonHeader(bool UseOffsets, dwarf::UnitType UT) { // Emit size of content not including length itself - Asm->OutStreamer->AddComment("Length of Unit"); if (!DD->useSectionsAsReferences()) { StringRef Prefix = isDwoUnit() ? "debug_info_dwo_" : "debug_info_"; MCSymbol *BeginLabel = Asm->createTempSymbol(Prefix + "start"); EndLabel = Asm->createTempSymbol(Prefix + "end"); - Asm->emitLabelDifference(EndLabel, BeginLabel, 4); + Asm->emitDwarfUnitLength(EndLabel, BeginLabel, "Length of Unit"); Asm->OutStreamer->emitLabel(BeginLabel); } else - Asm->emitInt32(getHeaderSize() + getUnitDie().getSize()); + Asm->emitDwarfUnitLength(getHeaderSize() + getUnitDie().getSize(), + "Length of Unit"); Asm->OutStreamer->AddComment("DWARF version number"); unsigned Version = DD->getDwarfVersion(); @@ -1759,10 +1759,7 @@ DwarfUnit::addSectionLabel(DIE &Die, dwarf::Attribute Attribute, const MCSymbol *Label, const MCSymbol *Sec) { if (Asm->MAI->doesDwarfUseRelocationsAcrossSections()) - return addLabel(Die, Attribute, - DD->getDwarfVersion() >= 4 ? dwarf::DW_FORM_sec_offset - : dwarf::DW_FORM_data4, - Label); + return addLabel(Die, Attribute, DD->getDwarfSectionOffsetForm(), Label); return addSectionDelta(Die, Attribute, Label, Sec); } diff --git a/llvm/test/DebugInfo/X86/debug-info-dwarf64.ll b/llvm/test/DebugInfo/X86/debug-info-dwarf64.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/X86/debug-info-dwarf64.ll @@ -0,0 +1,63 @@ +; This checks that .debug_info can be generated in the DWARF64 format. + +; RUN: llc -mtriple=x86_64 -dwarf-version=3 -dwarf64 -filetype=obj %s -o %t3 +; RUN: llvm-dwarfdump -debug-abbrev -debug-info -v %t3 | \ +; RUN: FileCheck %s --check-prefixes=CHECK,DWARFv3 + +; RUN: llc -mtriple=x86_64 -dwarf-version=4 -dwarf64 -filetype=obj %s -o %t4 +; RUN: llvm-dwarfdump -debug-abbrev -debug-info -v %t4 | \ +; RUN: FileCheck %s --check-prefixes=CHECK,DWARFv4 + +; CHECK: .debug_abbrev contents: +; CHECK: [1] DW_TAG_compile_unit DW_CHILDREN_yes +; CHECK-NEXT: DW_AT_producer DW_FORM_strp +; CHECK-NEXT: DW_AT_language DW_FORM_data2 +; CHECK-NEXT: DW_AT_name DW_FORM_strp +; DWARFv3-NEXT: DW_AT_stmt_list DW_FORM_data8 +; DWARFv4-NEXT: DW_AT_stmt_list DW_FORM_sec_offset +; CHECK-NEXT: DW_AT_comp_dir DW_FORM_strp +; CHECK: [2] DW_TAG_variable DW_CHILDREN_no +; CHECK-NEXT: DW_AT_name DW_FORM_strp +; CHECK-NEXT: DW_AT_type DW_FORM_ref4 +; CHECK: [3] DW_TAG_base_type DW_CHILDREN_no +; CHECK-NEXT: DW_AT_name DW_FORM_strp + +; CHECK: .debug_info contents: +; CHECK: Compile Unit: length = 0x{{([[:xdigit:]]{16})}}, format = DWARF64, +; CHECK: DW_TAG_compile_unit [1] * +; CHECK-NEXT: DW_AT_producer [DW_FORM_strp] ( .debug_str[0x{{([[:xdigit:]]{16})}}] = "clang version 12.0.0") +; CHECK-NEXT: DW_AT_language [DW_FORM_data2] (DW_LANG_C99) +; CHECK-NEXT: DW_AT_name [DW_FORM_strp] ( .debug_str[0x{{([[:xdigit:]]{16})}}] = "foo.c") +; DWARFv3-NEXT: DW_AT_stmt_list [DW_FORM_data8] (0x0000000000000000) +; DWARFv4-NEXT: DW_AT_stmt_list [DW_FORM_sec_offset] (0x0000000000000000) +; CHECK-NEXT: DW_AT_comp_dir [DW_FORM_strp] ( .debug_str[0x{{([[:xdigit:]]{16})}}] = "/tmp") +; CHECK: DW_TAG_variable [2] +; CHECK-NEXT: DW_AT_name [DW_FORM_strp] ( .debug_str[0x{{([[:xdigit:]]{16})}}] = "foo") +; CHECK-NEXT: DW_AT_type [DW_FORM_ref4] (cu + {{.+}} => {{.+}} "int") +; CHECK: DW_TAG_base_type [3] +; CHECK-NEXT: DW_AT_name [DW_FORM_strp] ( .debug_str[0x{{([[:xdigit:]]{16})}}] = "int") + +; IR generated and reduced from: +; $ cat foo.c +; int foo; +; $ clang -g -S -emit-llvm foo.c -o foo.ll + +target triple = "x86_64-unknown-linux-gnu" + +@foo = dso_local global i32 0, align 4, !dbg !0 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "foo", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 12.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "foo.c", directory: "/tmp") +!4 = !{} +!5 = !{!0} +!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!7 = !{i32 7, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{!"clang version 12.0.0"} diff --git a/llvm/unittests/CodeGen/DIETest.cpp b/llvm/unittests/CodeGen/DIETest.cpp --- a/llvm/unittests/CodeGen/DIETest.cpp +++ b/llvm/unittests/CodeGen/DIETest.cpp @@ -117,10 +117,12 @@ DIETestParams, DIELabelFixture, testing::Values( DIETestParams{4, dwarf::DWARF32, dwarf::DW_FORM_data4, 4u}, + DIETestParams{4, dwarf::DWARF32, dwarf::DW_FORM_data8, 8u}, DIETestParams{4, dwarf::DWARF32, dwarf::DW_FORM_sec_offset, 4u}, DIETestParams{4, dwarf::DWARF32, dwarf::DW_FORM_strp, 4u}, DIETestParams{4, dwarf::DWARF32, dwarf::DW_FORM_addr, 8u}, DIETestParams{4, dwarf::DWARF64, dwarf::DW_FORM_data4, 4u}, + DIETestParams{4, dwarf::DWARF64, dwarf::DW_FORM_data8, 8u}, DIETestParams{4, dwarf::DWARF64, dwarf::DW_FORM_sec_offset, 8u}, DIETestParams{4, dwarf::DWARF64, dwarf::DW_FORM_strp, 8u}, DIETestParams{4, dwarf::DWARF64, dwarf::DW_FORM_addr, 8u}), );