Index: llvm/include/llvm/MC/MCContext.h =================================================================== --- llvm/include/llvm/MC/MCContext.h +++ llvm/include/llvm/MC/MCContext.h @@ -185,6 +185,9 @@ /// The maximum version of dwarf that we should emit. uint16_t DwarfVersion = 4; + /// The format of dwarf that we emit. + dwarf::DwarfFormat DwarfFormat = dwarf::DWARF32; + /// Honor temporary labels, this is useful for debugging semantic /// differences between temporary and non-temporary labels (primarily on /// Darwin). @@ -694,10 +697,8 @@ void setDwarfDebugProducer(StringRef S) { DwarfDebugProducer = S; } StringRef getDwarfDebugProducer() { return DwarfDebugProducer; } - dwarf::DwarfFormat getDwarfFormat() const { - // TODO: Support DWARF64 - return dwarf::DWARF32; - } + void setDwarfFormat(dwarf::DwarfFormat f) { DwarfFormat = f; } + dwarf::DwarfFormat getDwarfFormat() const { return DwarfFormat; } void setDwarfVersion(uint16_t v) { DwarfVersion = v; } uint16_t getDwarfVersion() const { return DwarfVersion; } Index: llvm/include/llvm/MC/MCTargetOptions.h =================================================================== --- llvm/include/llvm/MC/MCTargetOptions.h +++ llvm/include/llvm/MC/MCTargetOptions.h @@ -53,6 +53,7 @@ /// Preserve Comments in Assembly. bool PreserveAsmComments : 1; + bool Dwarf64 : 1; int DwarfVersion = 0; std::string ABIName; Index: llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h =================================================================== --- llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h +++ llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h @@ -30,6 +30,8 @@ int getDwarfVersion(); +bool getDwarf64(); + bool getShowMCInst(); bool getFatalWarnings(); Index: llvm/lib/MC/MCDwarf.cpp =================================================================== --- llvm/lib/MC/MCDwarf.cpp +++ llvm/lib/MC/MCDwarf.cpp @@ -50,8 +50,14 @@ S.getContext().createTempSymbol("debug_list_header_start", true, true); MCSymbol *End = S.getContext().createTempSymbol("debug_list_header_end", true, true); + auto DwarfFormat = S.getContext().getDwarfFormat(); + if (DwarfFormat == dwarf::DWARF64) { + S.AddComment("DWARF64 mark"); + S.emitInt32(dwarf::DW_LENGTH_DWARF64); + } S.AddComment("Length"); - S.emitAbsoluteSymbolDiff(End, Start, 4); + S.emitAbsoluteSymbolDiff(End, Start, + dwarf::getDwarfOffsetByteSize(DwarfFormat)); S.emitLabel(Start); S.AddComment("Version"); S.emitInt16(S.getContext().getDwarfVersion()); @@ -332,7 +338,8 @@ } void MCDwarfLineStr::emitRef(MCStreamer *MCOS, StringRef Path) { - int RefSize = 4; // FIXME: Support DWARF-64 + int RefSize = + dwarf::getDwarfOffsetByteSize(MCOS->getContext().getDwarfFormat()); size_t Offset = LineStrings.add(Path); if (UseRelocs) { MCContext &Ctx = MCOS->getContext(); @@ -472,10 +479,20 @@ // Create a symbol for the end of the section (to be set when we get there). MCSymbol *LineEndSym = context.createTempSymbol(); - // The first 4 bytes is the total length of the information for this - // compilation unit (not including these 4 bytes for the length). - emitAbsValue( - *MCOS, MakeStartMinusEndExpr(context, *LineStartSym, *LineEndSym, 4), 4); + unsigned UnitLengthBytes = + dwarf::getUnitLengthFieldByteSize(context.getDwarfFormat()); + unsigned OffsetSize = dwarf::getDwarfOffsetByteSize(context.getDwarfFormat()); + + if (context.getDwarfFormat() == dwarf::DWARF64) + // Emit DWARF64 mark. + MCOS->emitInt32(dwarf::DW_LENGTH_DWARF64); + + // The length field does not include itself and, in case of the 64-bit DWARF + // format, the DWARF64 mark. + emitAbsValue(*MCOS, + MakeStartMinusEndExpr(context, *LineStartSym, *LineEndSym, + UnitLengthBytes), + OffsetSize); // Next 2 bytes is the Version. unsigned LineTableVersion = context.getDwarfVersion(); @@ -483,7 +500,7 @@ // Keep track of the bytes between the very start and where the header length // comes out. - unsigned PreHeaderLengthBytes = 4 + 2; + unsigned PreHeaderLengthBytes = UnitLengthBytes + 2; // In v5, we get address info next. if (LineTableVersion >= 5) { @@ -495,12 +512,12 @@ // Create a symbol for the end of the prologue (to be set when we get there). MCSymbol *ProEndSym = context.createTempSymbol(); // Lprologue_end - // Length of the prologue, is the next 4 bytes. This is actually the length - // from after the length word, to the end of the prologue. + // Length of the prologue, is the next 4 bytes (8 bytes for DWARF64). This is + // actually the length from after the length word, to the end of the prologue. emitAbsValue(*MCOS, MakeStartMinusEndExpr(context, *LineStartSym, *ProEndSym, - (PreHeaderLengthBytes + 4)), - 4); + (PreHeaderLengthBytes + OffsetSize)), + OffsetSize); // Parameters of the state machine, are next. MCOS->emitInt8(context.getAsmInfo()->getMinInstAlignment()); @@ -816,14 +833,15 @@ MCOS->emitULEB128IntValue(1); MCOS->emitULEB128IntValue(dwarf::DW_TAG_compile_unit); MCOS->emitInt8(dwarf::DW_CHILDREN_yes); - EmitAbbrev(MCOS, dwarf::DW_AT_stmt_list, context.getDwarfVersion() >= 4 - ? dwarf::DW_FORM_sec_offset - : dwarf::DW_FORM_data4); + dwarf::Form SecOffsetForm = + context.getDwarfVersion() >= 4 + ? dwarf::DW_FORM_sec_offset + : (context.getDwarfFormat() == dwarf::DWARF64 ? dwarf::DW_FORM_data8 + : dwarf::DW_FORM_data4); + EmitAbbrev(MCOS, dwarf::DW_AT_stmt_list, SecOffsetForm); if (context.getGenDwarfSectionSyms().size() > 1 && context.getDwarfVersion() >= 3) { - EmitAbbrev(MCOS, dwarf::DW_AT_ranges, context.getDwarfVersion() >= 4 - ? dwarf::DW_FORM_sec_offset - : dwarf::DW_FORM_data4); + EmitAbbrev(MCOS, dwarf::DW_AT_ranges, SecOffsetForm); } else { EmitAbbrev(MCOS, dwarf::DW_AT_low_pc, dwarf::DW_FORM_addr); EmitAbbrev(MCOS, dwarf::DW_AT_high_pc, dwarf::DW_FORM_addr); @@ -871,9 +889,13 @@ MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfARangesSection()); + unsigned UnitLengthBytes = + dwarf::getUnitLengthFieldByteSize(context.getDwarfFormat()); + unsigned OffsetSize = dwarf::getDwarfOffsetByteSize(context.getDwarfFormat()); + // This will be the length of the .debug_aranges section, first account for // the size of each item in the header (see below where we emit these items). - int Length = 4 + 2 + 4 + 1 + 1; + int Length = UnitLengthBytes + 2 + OffsetSize + 1 + 1; // Figure the padding after the header before the table of address and size // pairs who's values are PointerSize'ed. @@ -891,17 +913,21 @@ Length += 2 * AddrSize; // Emit the header for this section. - // The 4 byte length not including the 4 byte value for the length. - MCOS->emitInt32(Length - 4); + if (context.getDwarfFormat() == dwarf::DWARF64) + // The DWARF64 mark. + MCOS->emitInt32(dwarf::DW_LENGTH_DWARF64); + // The 4 (8 for DWARF64) byte length not including the length of the unit + // length field itself. + MCOS->emitIntValue(Length - UnitLengthBytes, OffsetSize); // The 2 byte version, which is 2. MCOS->emitInt16(2); - // The 4 byte offset to the compile unit in the .debug_info from the start - // of the .debug_info. + // The 4 (8 for DWARF64) byte offset to the compile unit in the .debug_info + // from the start of the .debug_info. if (InfoSectionSymbol) - MCOS->emitSymbolValue(InfoSectionSymbol, 4, + MCOS->emitSymbolValue(InfoSectionSymbol, OffsetSize, asmInfo->needsDwarfSectionOffsetDirective()); else - MCOS->emitInt32(0); + MCOS->emitIntValue(0, OffsetSize); // The 1 byte size of an address. MCOS->emitInt8(AddrSize); // The 1 byte size of a segment descriptor, we use a value of zero. @@ -950,11 +976,19 @@ // First part: the header. - // The 4 byte total length of the information for this compilation unit, not - // including these 4 bytes. + unsigned UnitLengthBytes = + dwarf::getUnitLengthFieldByteSize(context.getDwarfFormat()); + unsigned OffsetSize = dwarf::getDwarfOffsetByteSize(context.getDwarfFormat()); + + if (context.getDwarfFormat() == dwarf::DWARF64) + // Emit DWARF64 mark. + MCOS->emitInt32(dwarf::DW_LENGTH_DWARF64); + + // The 4 (8 for DWARF64) byte total length of the information for this + // compilation unit, not including the unit length field itself. const MCExpr *Length = - MakeStartMinusEndExpr(context, *InfoStart, *InfoEnd, 4); - emitAbsValue(*MCOS, Length, 4); + MakeStartMinusEndExpr(context, *InfoStart, *InfoEnd, UnitLengthBytes); + emitAbsValue(*MCOS, Length, OffsetSize); // The 2 byte DWARF version. MCOS->emitInt16(context.getDwarfVersion()); @@ -967,12 +1001,12 @@ MCOS->emitInt8(dwarf::DW_UT_compile); MCOS->emitInt8(AddrSize); } - // The 4 byte offset to the debug abbrevs from the start of the .debug_abbrev, - // it is at the start of that section so this is zero. + // The 4 (8 for DWARF64) byte offset to the debug abbrevs from the start of + // the .debug_abbrev, it is at the start of that section so this is zero. if (AbbrevSectionSymbol == nullptr) - MCOS->emitInt32(0); + MCOS->emitIntValue(0, OffsetSize); else - MCOS->emitSymbolValue(AbbrevSectionSymbol, 4, + MCOS->emitSymbolValue(AbbrevSectionSymbol, OffsetSize, AsmInfo.needsDwarfSectionOffsetDirective()); if (context.getDwarfVersion() <= 4) MCOS->emitInt8(AddrSize); @@ -982,19 +1016,19 @@ // The DW_TAG_compile_unit DIE abbrev (1). MCOS->emitULEB128IntValue(1); - // DW_AT_stmt_list, a 4 byte offset from the start of the .debug_line section, - // which is at the start of that section so this is zero. + // DW_AT_stmt_list, a 4 (8 for DWARF64) byte offset from the start of the + // .debug_line section, which is at the start of that section so this is zero. if (LineSectionSymbol) - MCOS->emitSymbolValue(LineSectionSymbol, 4, + MCOS->emitSymbolValue(LineSectionSymbol, OffsetSize, AsmInfo.needsDwarfSectionOffsetDirective()); else - MCOS->emitInt32(0); + MCOS->emitIntValue(0, OffsetSize); if (RangesSymbol) { // There are multiple sections containing code, so we must use - // .debug_ranges/.debug_rnglists. AT_ranges, the 4 byte offset from the + // .debug_ranges/.debug_rnglists. AT_ranges, the 4/8 byte offset from the // start of the .debug_ranges/.debug_rnglists. - MCOS->emitSymbolValue(RangesSymbol, 4); + MCOS->emitSymbolValue(RangesSymbol, OffsetSize); } else { // If we only have one non-empty code section, we can use the simpler // AT_low_pc and AT_high_pc attributes. @@ -1594,14 +1628,25 @@ MCSymbol *sectionEnd = context.createTempSymbol(); + unsigned UnitLengthBytes = + IsEH ? 4 : dwarf::getUnitLengthFieldByteSize(context.getDwarfFormat()); + unsigned OffsetSize = + IsEH ? 4 : dwarf::getDwarfOffsetByteSize(context.getDwarfFormat()); + bool IsDwarf64 = context.getDwarfFormat() == dwarf::DWARF64; + + if (!IsEH && IsDwarf64) + // DWARF64 mark + Streamer.emitInt32(dwarf::DW_LENGTH_DWARF64); + // Length - const MCExpr *Length = - MakeStartMinusEndExpr(context, *sectionStart, *sectionEnd, 4); - emitAbsValue(Streamer, Length, 4); + const MCExpr *Length = MakeStartMinusEndExpr(context, *sectionStart, + *sectionEnd, UnitLengthBytes); + emitAbsValue(Streamer, Length, OffsetSize); // CIE ID - unsigned CIE_ID = IsEH ? 0 : -1; - Streamer.emitInt32(CIE_ID); + uint64_t CIE_ID = + IsEH ? 0 : (IsDwarf64 ? dwarf::DW64_CIE_ID : dwarf::DW_CIE_ID); + Streamer.emitIntValue(CIE_ID, OffsetSize); // Version uint8_t CIEVersion = getCIEVersion(IsEH, context.getDwarfVersion()); @@ -1711,9 +1756,16 @@ CFAOffset = InitialCFAOffset; + unsigned OffsetSize = + IsEH ? 4 : dwarf::getDwarfOffsetByteSize(context.getDwarfFormat()); + + if (!IsEH && context.getDwarfFormat() == dwarf::DWARF64) + // DWARF64 mark + Streamer.emitInt32(dwarf::DW_LENGTH_DWARF64); + // Length const MCExpr *Length = MakeStartMinusEndExpr(context, *fdeStart, *fdeEnd, 0); - emitAbsValue(Streamer, Length, 4); + emitAbsValue(Streamer, Length, OffsetSize); Streamer.emitLabel(fdeStart); @@ -1722,13 +1774,13 @@ if (IsEH) { const MCExpr *offset = MakeStartMinusEndExpr(context, cieStart, *fdeStart, 0); - emitAbsValue(Streamer, offset, 4); + emitAbsValue(Streamer, offset, OffsetSize); } else if (!asmInfo->doesDwarfUseRelocationsAcrossSections()) { const MCExpr *offset = MakeStartMinusEndExpr(context, SectionStart, cieStart, 0); - emitAbsValue(Streamer, offset, 4); + emitAbsValue(Streamer, offset, OffsetSize); } else { - Streamer.emitSymbolValue(&cieStart, 4, + Streamer.emitSymbolValue(&cieStart, OffsetSize, asmInfo->needsDwarfSectionOffsetDirective()); } Index: llvm/lib/MC/MCTargetOptions.cpp =================================================================== --- llvm/lib/MC/MCTargetOptions.cpp +++ llvm/lib/MC/MCTargetOptions.cpp @@ -16,7 +16,7 @@ MCNoWarn(false), MCNoDeprecatedWarn(false), MCSaveTempLabels(false), MCUseDwarfDirectory(false), MCIncrementalLinkerCompatible(false), ShowMCEncoding(false), ShowMCInst(false), AsmVerbose(false), - PreserveAsmComments(true) {} + PreserveAsmComments(true), Dwarf64(false) {} StringRef MCTargetOptions::getABIName() const { return ABIName; Index: llvm/lib/MC/MCTargetOptionsCommandFlags.cpp =================================================================== --- llvm/lib/MC/MCTargetOptionsCommandFlags.cpp +++ llvm/lib/MC/MCTargetOptionsCommandFlags.cpp @@ -38,6 +38,7 @@ MCOPT_EXP(bool, RelaxAll) MCOPT(bool, IncrementalLinkerCompatible) MCOPT(int, DwarfVersion) +MCOPT(bool, Dwarf64) MCOPT(bool, ShowMCInst) MCOPT(bool, FatalWarnings) MCOPT(bool, NoWarn) @@ -66,6 +67,11 @@ cl::init(0)); MCBINDOPT(DwarfVersion); + static cl::opt Dwarf64( + "dwarf64", + cl::desc("Generate debugging info in the 64-bit DWARF format")); + MCBINDOPT(Dwarf64); + static cl::opt ShowMCInst( "asm-show-inst", cl::desc("Emit internal instruction representation to assembly file")); @@ -97,6 +103,7 @@ MCTargetOptions Options; Options.MCRelaxAll = getRelaxAll(); Options.MCIncrementalLinkerCompatible = getIncrementalLinkerCompatible(); + Options.Dwarf64 = getDwarf64(); Options.DwarfVersion = getDwarfVersion(); Options.ShowMCInst = getShowMCInst(); Options.ABIName = getABIName(); Index: llvm/test/MC/COFF/dwarf64-err.s =================================================================== --- /dev/null +++ llvm/test/MC/COFF/dwarf64-err.s @@ -0,0 +1,3 @@ +# RUN: not llvm-mc -dwarf64 -triple x86_64-unknown-windows-gnu %s -o - 2>&1 | FileCheck %s + +# CHECK: the 64-bit DWARF format is not supported for x86_64-unknown-windows-gnu. Index: llvm/test/MC/ELF/gen-dwarf64.s =================================================================== --- /dev/null +++ llvm/test/MC/ELF/gen-dwarf64.s @@ -0,0 +1,95 @@ +// RUN: not llvm-mc -g -dwarf-version 5 -dwarf64 -triple i686 %s -filetype=asm -o - 2>&1 | FileCheck --check-prefix=I686 %s +// RUN: not llvm-mc -g -dwarf-version 2 -dwarf64 -triple x86_64 %s -filetype=asm -o - 2>&1 | FileCheck --check-prefix=DWARF2 %s + +// RUN: llvm-mc -g -dwarf-version 3 -dwarf64 -triple x86_64 %s -filetype=obj -o %t3.o +// RUN: llvm-mc -g -dwarf-version 5 -dwarf64 -triple x86_64 %s -filetype=obj -o %t5.o + +// RUN: llvm-readobj -r %t3.o | FileCheck --check-prefixes=REL,REL3 %s +// RUN: llvm-readobj -r %t5.o | FileCheck --check-prefixes=REL,REL5 %s + +// RUN: llvm-dwarfdump -v %t3.o | FileCheck --check-prefixes=DUMP,DUMP3 %s +// RUN: llvm-dwarfdump -v %t5.o | FileCheck --check-prefixes=DUMP,DUMP5 %s + +// DWARF2: the 64-bit DWARF format is not supported for DWARF versions prior to 3. +// I686: the 64-bit DWARF format is only supported for 64-bit targets. + +// REL: Relocations [ +// REL: Section ({{[0-9]+}}) .rela.debug_frame { +// REL-NEXT: R_X86_64_64 .debug_frame 0x0 +// REL-NEXT: R_X86_64_64 .bar 0x0 +// REL-NEXT: } +// REL-NEXT: Section ({{[0-9]+}}) .rela.debug_info { +// REL-NEXT: R_X86_64_64 .debug_abbrev 0x0 +// REL-NEXT: R_X86_64_64 .debug_line 0x0 +// REL3-NEXT: R_X86_64_64 .debug_ranges 0x0 +// REL5-NEXT: R_X86_64_64 .debug_rnglists 0x14 +// REL-NEXT: R_X86_64_64 .foo 0x0 +// REL-NEXT: R_X86_64_64 .bar 0x0 +// REL-NEXT: } +// REL-NEXT: Section ({{[0-9]+}}) .rela.debug_aranges { +// REL-NEXT: R_X86_64_64 .debug_info 0x0 +// REL-NEXT: R_X86_64_64 .foo 0x0 +// REL-NEXT: R_X86_64_64 .bar 0x0 +// REL-NEXT: } +// REL3-NEXT: Section ({{[0-9]+}}) .rela.debug_ranges { +// REL5-NEXT: Section ({{[0-9]+}}) .rela.debug_rnglists { +// REL-NEXT: R_X86_64_64 .foo 0x0 +// REL-NEXT: R_X86_64_64 .bar 0x0 +// REL-NEXT: } +// REL-NEXT: Section ({{[0-9]+}}) .rela.debug_line { +// REL5-NEXT: R_X86_64_64 .debug_line_str 0x0 +// REL5-NEXT: R_X86_64_64 .debug_line_str 0x +// REL-NEXT: R_X86_64_64 .foo 0x0 +// REL-NEXT: R_X86_64_64 .bar 0x0 +// REL-NEXT: } +// REL-NEXT: ] + +// DUMP: .debug_abbrev contents: +// DUMP3: DW_AT_stmt_list DW_FORM_data8 +// DUMP3-NEXT: DW_AT_ranges DW_FORM_data8 +// DUMP5: DW_AT_stmt_list DW_FORM_sec_offset +// DUMP5-NEXT: DW_AT_ranges DW_FORM_sec_offset + +// DUMP: .debug_info contents: +// DUMP-NEXT: 0x00000000: Compile Unit: +// DUMP-SAME: format = DWARF64 + +// DUMP: .debug_frame contents: +// DUMP: ffffffffffffffff CIE +// DUMP-NEXT: Format: DWARF64 +// DUMP: 0000000000000000 FDE cie=00000000 +// DUMP-NEXT: Format: DWARF64 + +// DUMP: .debug_aranges contents: +// DUMP-NEXT: Address Range Header: +// DUMP-SAME: format = DWARF64 + +// DUMP: .debug_line contents: +// DUMP-NEXT: debug_line[0x00000000] +// DUMP-NEXT: Line table prologue: +// DUMP-NEXT: total_length: +// DUMP-NEXT: format: DWARF64 +// DUMP5: include_directories[ 0] = .debug_line_str[0x0000000000000000] = "[[DIR:[^"]+]]" +// DUMP5-NEXT: file_names[ 0]: +// DUMP5-NEXT: name: .debug_line_str[0x00000000[[FILEOFF:[0-9a-f]+]]] = "[[FILE:[^"]+]]" +// DUMP5-NEXT: dir_index: 0 + +// DUMP5: .debug_line_str contents: +// DUMP5-NEXT: 0x00000000: "[[DIR]]" +// DUMP5-NEXT: 0x[[FILEOFF]]: "[[FILE]]" + +// DUMP5: .debug_rnglists contents: +// DUMP5-NEXT: 0x00000000: range list header: +// DUMP5-SAME: format = DWARF64 + + .cfi_sections .debug_frame + + .section .foo, "ax", @progbits +foo: + nop + + .section .bar, "ax", @progbits +bar: + .cfi_startproc + nop + .cfi_endproc Index: llvm/tools/llvm-mc/llvm-mc.cpp =================================================================== --- llvm/tools/llvm-mc/llvm-mc.cpp +++ llvm/tools/llvm-mc/llvm-mc.cpp @@ -387,6 +387,31 @@ return 1; } Ctx.setDwarfVersion(DwarfVersion); + if (MCOptions.Dwarf64) { + // DWARFv3 was the first standard where the 64-bit DWARF was described. + if (DwarfVersion < 3) { + errs() << ProgName + << ": the 64-bit DWARF format is not supported for DWARF versions " + "prior to 3.\n"; + return 1; + } + // DWARF64 requires 64-bit relocations. They do not exist in 32-bit targets. + if (MAI->getCodePointerSize() < 8) { + errs() << ProgName + << ": the 64-bit DWARF format is only supported for 64-bit " + "targets.\n"; + return 1; + } + // If needsDwarfSectionOffsetDirective is true, we would eventually call + // MCStreamer::emitSymbolValue() with IsSectionRelative = true, but that + // is supported only for 4-byte long references. + if (MAI->needsDwarfSectionOffsetDirective()) { + errs() << ProgName << ": the 64-bit DWARF format is not supported for " + << TheTriple.normalize() << ".\n"; + return 1; + } + Ctx.setDwarfFormat(dwarf::DWARF64); + } if (!DwarfDebugFlags.empty()) Ctx.setDwarfDebugFlags(StringRef(DwarfDebugFlags)); if (!DwarfDebugProducer.empty())