From 5c63af0d040a377c4fe13a75dea5bb6f84116b9e Mon Sep 17 00:00:00 2001 From: Hsiangkai Wang Date: Wed, 1 Aug 2018 02:18:06 +0000 Subject: [PATCH] [DebugInfo] Generate fixups as emitting DWARF .debug_line. It is necessary to generate fixups in .debug_line as relaxation is enabled due to the address delta may be changed after relaxation. DWARF will record the mappings of lines and addresses in .debug_line section. It will encode the information using special opcodes, standard opcodes and extended opcodes in Line Number Program. I use DW_LNS_fixed_advance_pc to encode fixed length address delta and DW_LNE_set_address to encode absolute address to make it possible to generate fixups in .debug_line section. Differential Revision: https://reviews.llvm.org/D46850 llvm-svn: 338477 --- llvm/include/llvm/MC/MCDwarf.h | 7 +++ llvm/include/llvm/MC/MCFragment.h | 16 ++---- llvm/lib/MC/MCAssembler.cpp | 36 ++++++++++--- llvm/lib/MC/MCDwarf.cpp | 51 ++++++++++++++++++ llvm/test/DebugInfo/RISCV/lit.local.cfg | 2 + llvm/test/DebugInfo/RISCV/relax-debug-line.ll | 75 +++++++++++++++++++++++++++ 6 files changed, 170 insertions(+), 17 deletions(-) create mode 100644 llvm/test/DebugInfo/RISCV/lit.local.cfg create mode 100644 llvm/test/DebugInfo/RISCV/relax-debug-line.ll diff --git a/llvm/include/llvm/MC/MCDwarf.h b/llvm/include/llvm/MC/MCDwarf.h index 785f42d..2bfaf19c 100644 --- a/llvm/include/llvm/MC/MCDwarf.h +++ b/llvm/include/llvm/MC/MCDwarf.h @@ -362,6 +362,13 @@ public: static void Encode(MCContext &Context, MCDwarfLineTableParams Params, int64_t LineDelta, uint64_t AddrDelta, raw_ostream &OS); + /// Utility function to encode a Dwarf pair of LineDelta and AddrDeltas using + /// fixed length operands. + static bool FixedEncode(MCContext &Context, + MCDwarfLineTableParams Params, + int64_t LineDelta, uint64_t AddrDelta, + raw_ostream &OS, uint32_t *Offset, uint32_t *Size); + /// Utility function to emit the encoding to a streamer. static void Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params, int64_t LineDelta, uint64_t AddrDelta); diff --git a/llvm/include/llvm/MC/MCFragment.h b/llvm/include/llvm/MC/MCFragment.h index 47b3517..c999c9f 100644 --- a/llvm/include/llvm/MC/MCFragment.h +++ b/llvm/include/llvm/MC/MCFragment.h @@ -149,6 +149,7 @@ public: case MCFragment::FT_Relaxable: case MCFragment::FT_CompactEncodedInst: case MCFragment::FT_Data: + case MCFragment::FT_Dwarf: return true; } } @@ -232,7 +233,7 @@ public: static bool classof(const MCFragment *F) { MCFragment::FragmentType Kind = F->getKind(); return Kind == MCFragment::FT_Relaxable || Kind == MCFragment::FT_Data || - Kind == MCFragment::FT_CVDefRange; + Kind == MCFragment::FT_CVDefRange || Kind == MCFragment::FT_Dwarf;; } }; @@ -514,7 +515,7 @@ public: } }; -class MCDwarfLineAddrFragment : public MCFragment { +class MCDwarfLineAddrFragment : public MCEncodedFragmentWithFixups<8, 1> { /// LineDelta - the value of the difference between the two line numbers /// between two .loc dwarf directives. int64_t LineDelta; @@ -523,15 +524,11 @@ class MCDwarfLineAddrFragment : public MCFragment { /// make up the address delta between two .loc dwarf directives. const MCExpr *AddrDelta; - SmallString<8> Contents; - public: MCDwarfLineAddrFragment(int64_t LineDelta, const MCExpr &AddrDelta, MCSection *Sec = nullptr) - : MCFragment(FT_Dwarf, false, Sec), LineDelta(LineDelta), - AddrDelta(&AddrDelta) { - Contents.push_back(0); - } + : MCEncodedFragmentWithFixups<8, 1>(FT_Dwarf, false, Sec), + LineDelta(LineDelta), AddrDelta(&AddrDelta) {} /// \name Accessors /// @{ @@ -540,9 +537,6 @@ public: const MCExpr &getAddrDelta() const { return *AddrDelta; } - SmallString<8> &getContents() { return Contents; } - const SmallString<8> &getContents() const { return Contents; } - /// @} static bool classof(const MCFragment *F) { diff --git a/llvm/lib/MC/MCAssembler.cpp b/llvm/lib/MC/MCAssembler.cpp index d54e51f..d3a84e2 100644 --- a/llvm/lib/MC/MCAssembler.cpp +++ b/llvm/lib/MC/MCAssembler.cpp @@ -822,6 +822,9 @@ void MCAssembler::layout(MCAsmLayout &Layout) { } else if (auto *FragWithFixups = dyn_cast(&Frag)) { Fixups = FragWithFixups->getFixups(); Contents = FragWithFixups->getContents(); + } else if (auto *FragWithFixups = dyn_cast(&Frag)) { + Fixups = FragWithFixups->getFixups(); + Contents = FragWithFixups->getContents(); } else llvm_unreachable("Unknown fragment with fixups!"); for (const MCFixup &Fixup : Fixups) { @@ -951,16 +954,37 @@ bool MCAssembler::relaxDwarfLineAddr(MCAsmLayout &Layout, MCContext &Context = Layout.getAssembler().getContext(); uint64_t OldSize = DF.getContents().size(); int64_t AddrDelta; - bool Abs = DF.getAddrDelta().evaluateKnownAbsolute(AddrDelta, Layout); - assert(Abs && "We created a line delta with an invalid expression"); - (void) Abs; + bool Abs = DF.getAddrDelta().evaluateAsAbsolute(AddrDelta, Layout); int64_t LineDelta; LineDelta = DF.getLineDelta(); - SmallString<8> &Data = DF.getContents(); + SmallVectorImpl &Data = DF.getContents(); Data.clear(); raw_svector_ostream OSE(Data); - MCDwarfLineAddr::Encode(Context, getDWARFLinetableParams(), LineDelta, - AddrDelta, OSE); + DF.getFixups().clear(); + + if (Abs) { + MCDwarfLineAddr::Encode(Context, getDWARFLinetableParams(), LineDelta, + AddrDelta, OSE); + } else { + uint32_t Offset; + uint32_t Size; + bool SetDelta = MCDwarfLineAddr::FixedEncode(Context, + getDWARFLinetableParams(), + LineDelta, AddrDelta, + OSE, &Offset, &Size); + // Add Fixups for address delta or new address. + const MCExpr *FixupExpr; + if (SetDelta) { + FixupExpr = &DF.getAddrDelta(); + } else { + const MCBinaryExpr *ABE = cast(&DF.getAddrDelta()); + FixupExpr = ABE->getLHS(); + } + DF.getFixups().push_back( + MCFixup::create(Offset, FixupExpr, + MCFixup::getKindForSize(Size, false /*isPCRel*/))); + } + return OldSize != Data.size(); } diff --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp index a02cddb..0461c25 100644 --- a/llvm/lib/MC/MCDwarf.cpp +++ b/llvm/lib/MC/MCDwarf.cpp @@ -731,6 +731,57 @@ void MCDwarfLineAddr::Encode(MCContext &Context, MCDwarfLineTableParams Params, } } +bool MCDwarfLineAddr::FixedEncode(MCContext &Context, + MCDwarfLineTableParams Params, + int64_t LineDelta, uint64_t AddrDelta, + raw_ostream &OS, + uint32_t *Offset, uint32_t *Size) { + if (LineDelta != INT64_MAX) { + OS << char(dwarf::DW_LNS_advance_line); + encodeSLEB128(LineDelta, OS); + } + + // Use address delta to adjust address or use absolute address to adjust + // address. + bool SetDelta; + // According to DWARF spec., the DW_LNS_fixed_advance_pc opcode takes a + // single uhalf (unencoded) operand. So, the maximum value of AddrDelta + // is 65535. We set a conservative upper bound for it for relaxation. + if (AddrDelta > 60000) { + const MCAsmInfo *asmInfo = Context.getAsmInfo(); + unsigned AddrSize = asmInfo->getCodePointerSize(); + + OS << char(dwarf::DW_LNS_extended_op); + encodeULEB128(1 + AddrSize, OS); + OS << char(dwarf::DW_LNE_set_address); + // Generate fixup for the address. + *Offset = OS.tell(); + *Size = AddrSize; + SetDelta = false; + std::vector FillData; + FillData.insert(FillData.begin(), AddrSize, 0); + OS.write(reinterpret_cast(FillData.data()), AddrSize); + } else { + OS << char(dwarf::DW_LNS_fixed_advance_pc); + // Generate fixup for 2-bytes address delta. + *Offset = OS.tell(); + *Size = 2; + SetDelta = true; + OS << char(0); + OS << char(0); + } + + if (LineDelta == INT64_MAX) { + OS << char(dwarf::DW_LNS_extended_op); + OS << char(1); + OS << char(dwarf::DW_LNE_end_sequence); + } else { + OS << char(dwarf::DW_LNS_copy); + } + + return SetDelta; +} + // Utility function to write a tuple for .debug_abbrev. static void EmitAbbrev(MCStreamer *MCOS, uint64_t Name, uint64_t Form) { MCOS->EmitULEB128IntValue(Name); diff --git a/llvm/test/DebugInfo/RISCV/lit.local.cfg b/llvm/test/DebugInfo/RISCV/lit.local.cfg new file mode 100644 index 0000000..c638201 --- /dev/null +++ b/llvm/test/DebugInfo/RISCV/lit.local.cfg @@ -0,0 +1,2 @@ +if not 'RISCV' in config.root.targets: + config.unsupported = True diff --git a/llvm/test/DebugInfo/RISCV/relax-debug-line.ll b/llvm/test/DebugInfo/RISCV/relax-debug-line.ll new file mode 100644 index 0000000..814b253 --- /dev/null +++ b/llvm/test/DebugInfo/RISCV/relax-debug-line.ll @@ -0,0 +1,75 @@ +; RUN: llc -filetype=obj -mtriple=riscv32 -mattr=+relax %s -o - \ +; RUN: | llvm-readobj -r | FileCheck -check-prefix=RELAX %s +; +; RELAX: .rela.debug_line { +; RELAX: R_RISCV_ADD16 +; RELAX: R_RISCV_SUB16 +source_filename = "line.c" + +; Function Attrs: noinline nounwind optnone +define i32 @init() !dbg !7 { +entry: + ret i32 0, !dbg !11 +} + +; Function Attrs: noinline nounwind optnone +define i32 @foo(i32 signext %value) !dbg !12 { +entry: + %value.addr = alloca i32, align 4 + store i32 %value, i32* %value.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %value.addr, metadata !15, metadata !DIExpression()), !dbg !16 + %0 = load i32, i32* %value.addr, align 4, !dbg !17 + ret i32 %0, !dbg !18 +} + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.declare(metadata, metadata, metadata) + +; Function Attrs: noinline nounwind optnone +define i32 @bar() !dbg !19 { +entry: + %result = alloca i32, align 4 + %v = alloca i32, align 4 + call void @llvm.dbg.declare(metadata i32* %result, metadata !20, metadata !DIExpression()), !dbg !21 + call void @llvm.dbg.declare(metadata i32* %v, metadata !22, metadata !DIExpression()), !dbg !23 + %call = call i32 @init(), !dbg !24 + store i32 %call, i32* %v, align 4, !dbg !23 + %0 = load i32, i32* %v, align 4, !dbg !25 + %call1 = call i32 @foo(i32 signext %0), !dbg !26 + store i32 %call1, i32* %result, align 4, !dbg !27 + %1 = load i32, i32* %result, align 4, !dbg !28 + ret i32 %1, !dbg !29 +} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "line.c", directory: "./") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!7 = distinct !DISubprogram(name: "init", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: false, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{!10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DILocation(line: 3, column: 3, scope: !7) +!12 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 6, type: !13, isLocal: false, isDefinition: true, scopeLine: 7, flags: DIFlagPrototyped, isOptimized: false, unit: !0, retainedNodes: !2) +!13 = !DISubroutineType(types: !14) +!14 = !{!10, !10} +!15 = !DILocalVariable(name: "value", arg: 1, scope: !12, file: !1, line: 6, type: !10) +!16 = !DILocation(line: 6, column: 13, scope: !12) +!17 = !DILocation(line: 8, column: 10, scope: !12) +!18 = !DILocation(line: 8, column: 3, scope: !12) +!19 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 11, type: !8, isLocal: false, isDefinition: true, scopeLine: 12, isOptimized: false, unit: !0, retainedNodes: !2) +!20 = !DILocalVariable(name: "result", scope: !19, file: !1, line: 13, type: !10) +!21 = !DILocation(line: 13, column: 7, scope: !19) +!22 = !DILocalVariable(name: "v", scope: !19, file: !1, line: 14, type: !10) +!23 = !DILocation(line: 14, column: 7, scope: !19) +!24 = !DILocation(line: 14, column: 11, scope: !19) +!25 = !DILocation(line: 16, column: 16, scope: !19) +!26 = !DILocation(line: 16, column: 12, scope: !19) +!27 = !DILocation(line: 16, column: 10, scope: !19) +!28 = !DILocation(line: 18, column: 10, scope: !19) +!29 = !DILocation(line: 18, column: 3, scope: !19) -- 2.7.4