diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h index 0718e33f5645b..c16a52300c546 100644 --- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h @@ -159,6 +159,7 @@ class LLVM_ABI LVLocation : public LVObject { void print(raw_ostream &OS, bool Full = true) const override; void printExtra(raw_ostream &OS, bool Full = true) const override; + virtual void printLocations(raw_ostream &OS) const {} }; class LLVM_ABI LVLocationSymbol final : public LVLocation { @@ -179,6 +180,7 @@ class LLVM_ABI LVLocationSymbol final : public LVLocation { void printRawExtra(raw_ostream &OS, bool Full = true) const override; void printExtra(raw_ostream &OS, bool Full = true) const override; + void printLocations(raw_ostream &OS) const override; }; } // end namespace logicalview diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h index 1847fa8323480..1f8b884bc1b5d 100644 --- a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h +++ b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h @@ -159,7 +159,8 @@ class LVBinaryReader : public LVReader { LVAddress WasmCodeSectionOffset = 0; // Loads all info for the architecture of the provided object file. - Error loadGenericTargetInfo(StringRef TheTriple, StringRef TheFeatures); + Error loadGenericTargetInfo(StringRef TheTriple, StringRef TheFeatures, + StringRef CPU); virtual void mapRangeAddress(const object::ObjectFile &Obj) {} virtual void mapRangeAddress(const object::ObjectFile &Obj, diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp index 3c078d8ee74b8..4724f4f007163 100644 --- a/llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp +++ b/llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp @@ -648,6 +648,19 @@ void LVLocation::print(LVLocations *Locations, raw_ostream &OS, bool Full) { Location->print(OS, Full); } +void LVLocationSymbol::printLocations(raw_ostream &OS) const { + if (Entries) { + bool CodeViewLocation = getParentSymbol()->getHasCodeViewLocation(); + std::string Leading; + for (LVOperation *Operation : *Entries) { + OS << Leading + << (CodeViewLocation ? Operation->getOperandsCodeViewInfo() + : Operation->getOperandsDWARFInfo()); + Leading = ", "; + } + } +} + void LVLocationSymbol::printExtra(raw_ostream &OS, bool Full) const { OS << "{Location}"; if (getIsCallSite()) @@ -657,15 +670,9 @@ void LVLocationSymbol::printExtra(raw_ostream &OS, bool Full) const { // Print location entries. if (Full && Entries) { - bool CodeViewLocation = getParentSymbol()->getHasCodeViewLocation(); - std::stringstream Stream; - std::string Leading; - for (LVOperation *Operation : *Entries) { - Stream << Leading - << (CodeViewLocation ? Operation->getOperandsCodeViewInfo() - : Operation->getOperandsDWARFInfo()); - Leading = ", "; - } + std::string Str; + raw_string_ostream Stream(Str); + printLocations(Stream); printAttributes(OS, Full, "{Entry} ", const_cast(this), StringRef(Stream.str()), /*UseQuotes=*/false, diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp index 80b4185b7c600..414f0f3efc82d 100644 --- a/llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp +++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp @@ -275,7 +275,8 @@ void LVBinaryReader::mapVirtualAddress(const object::COFFObjectFile &COFFObj) { } Error LVBinaryReader::loadGenericTargetInfo(StringRef TheTriple, - StringRef TheFeatures) { + StringRef TheFeatures, + StringRef CPU) { std::string TargetLookupError; const Target *TheTarget = TargetRegistry::lookupTarget(TheTriple, TargetLookupError); @@ -298,7 +299,6 @@ Error LVBinaryReader::loadGenericTargetInfo(StringRef TheTriple, MAI.reset(AsmInfo); // Target subtargets. - StringRef CPU; MCSubtargetInfo *SubtargetInfo( TheTarget->createMCSubtargetInfo(TheTriple, CPU, TheFeatures)); if (!SubtargetInfo) diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewReader.cpp index e5895516b5e77..2ff70816b4bf1 100644 --- a/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewReader.cpp +++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewReader.cpp @@ -1190,7 +1190,12 @@ Error LVCodeViewReader::loadTargetInfo(const ObjectFile &Obj) { FeaturesValue = SubtargetFeatures(); } FeaturesValue = *Features; - return loadGenericTargetInfo(TT.str(), FeaturesValue.getString()); + + StringRef CPU; + if (auto OptCPU = Obj.tryGetCPUName()) + CPU = *OptCPU; + + return loadGenericTargetInfo(TT.str(), FeaturesValue.getString(), CPU); } Error LVCodeViewReader::loadTargetInfo(const PDBFile &Pdb) { @@ -1200,8 +1205,9 @@ Error LVCodeViewReader::loadTargetInfo(const PDBFile &Pdb) { TT.setOS(Triple::Win32); StringRef TheFeature = ""; + StringRef TheCPU = ""; - return loadGenericTargetInfo(TT.str(), TheFeature); + return loadGenericTargetInfo(TT.str(), TheFeature, TheCPU); } std::string LVCodeViewReader::getRegisterName(LVSmall Opcode, diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp index 696e2bc948a2e..3ba5061718144 100644 --- a/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp +++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp @@ -274,7 +274,7 @@ void LVDWARFReader::processOneAttribute(const DWARFDie &Die, for (DWARFAddressRange &Range : Ranges) { // This seems to be a tombstone for empty ranges. if ((Range.LowPC == Range.HighPC) || - (Range.LowPC = getTombstoneAddress())) + (Range.LowPC == getTombstoneAddress())) continue; // Store the real upper limit for the address range. if (UpdateHighAddress && Range.HighPC > 0) @@ -461,13 +461,17 @@ LVScope *LVDWARFReader::processOneDie(const DWARFDie &InputDIE, LVScope *Parent, if (!CurrentRanges.empty()) { for (LVAddressRange &Range : CurrentRanges) addSectionRange(SectionIndex, CurrentScope, Range.first, - Range.second); + Range.second > Range.first + ? Range.second - 1 // Make hi-pc exclusive + : Range.second); CurrentRanges.clear(); } // If the scope is the CU, do not update the ranges set. if (FoundLowPC && FoundHighPC && !IsCompileUnit) { addSectionRange(SectionIndex, CurrentScope, CurrentLowPC, - CurrentHighPC); + CurrentHighPC > CurrentLowPC + ? CurrentHighPC - 1 // Make hi-pc exclusive + : CurrentHighPC); } } } @@ -956,10 +960,7 @@ LVElement *LVDWARFReader::getElementForOffset(LVOffset Offset, Error LVDWARFReader::loadTargetInfo(const ObjectFile &Obj) { // Detect the architecture from the object file. We usually don't need OS // info to lookup a target and create register info. - Triple TT; - TT.setArch(Triple::ArchType(Obj.getArch())); - TT.setVendor(Triple::UnknownVendor); - TT.setOS(Triple::UnknownOS); + Triple TT = Obj.makeTriple(); // Features to be passed to target/subtarget Expected Features = Obj.getFeatures(); @@ -969,7 +970,12 @@ Error LVDWARFReader::loadTargetInfo(const ObjectFile &Obj) { FeaturesValue = SubtargetFeatures(); } FeaturesValue = *Features; - return loadGenericTargetInfo(TT.str(), FeaturesValue.getString()); + + StringRef CPU; + if (auto OptCPU = Obj.tryGetCPUName()) + CPU = *OptCPU; + + return loadGenericTargetInfo(TT.str(), FeaturesValue.getString(), CPU); } void LVDWARFReader::mapRangeAddress(const ObjectFile &Obj) { diff --git a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp index 8f89168754180..bf390e836078e 100644 --- a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp +++ b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp @@ -226,7 +226,8 @@ class ELFAMDGPUAsmBackend : public AMDGPUAsmBackend { public: ELFAMDGPUAsmBackend(const Target &T, const Triple &TT) : AMDGPUAsmBackend(T), Is64Bit(TT.isAMDGCN()), - HasRelocationAddend(TT.getOS() == Triple::AMDHSA) { + HasRelocationAddend(TT.getOS() == Triple::AMDHSA || + TT.getOS() == Triple::AMDPAL) { switch (TT.getOS()) { case Triple::AMDHSA: OSABI = ELF::ELFOSABI_AMDGPU_HSA; diff --git a/llvm/lib/Target/AMDGPU/SIPreAllocateWWMRegs.cpp b/llvm/lib/Target/AMDGPU/SIPreAllocateWWMRegs.cpp index 205a45a045a42..469a6525b4ac0 100644 --- a/llvm/lib/Target/AMDGPU/SIPreAllocateWWMRegs.cpp +++ b/llvm/lib/Target/AMDGPU/SIPreAllocateWWMRegs.cpp @@ -130,6 +130,9 @@ void SIPreAllocateWWMRegs::rewriteRegs(MachineFunction &MF) { if (VirtReg.isPhysical()) continue; + if (MI.isDebugInstr() && VirtReg == AMDGPU::NoRegister) + continue; + if (!VRM->hasPhys(VirtReg)) continue; diff --git a/llvm/test/CMakeLists.txt b/llvm/test/CMakeLists.txt index 2a6135da9a61e..7e0185e5ad9cc 100644 --- a/llvm/test/CMakeLists.txt +++ b/llvm/test/CMakeLists.txt @@ -86,6 +86,7 @@ set(LLVM_TEST_DEPENDS llvm-cxxfilt llvm-cxxmap llvm-debuginfo-analyzer + llvm-debuginfo-check llvm-debuginfod-find llvm-diff llvm-dis diff --git a/llvm/test/CodeGen/AMDGPU/amdgpu-llvm-debuginfo-check.ll b/llvm/test/CodeGen/AMDGPU/amdgpu-llvm-debuginfo-check.ll new file mode 100644 index 0000000000000..569c975409c37 --- /dev/null +++ b/llvm/test/CodeGen/AMDGPU/amdgpu-llvm-debuginfo-check.ll @@ -0,0 +1,115 @@ +; RUN: llc %s -o %t.o -mcpu=gfx1030 -filetype=obj -O0 +; RUN: llvm-debuginfo-check %t.o --vars | FileCheck %s + +; This test compiles this module with AMDGPU backend under -O0, +; and makes sure llvm-debuginfo-check works for it. + +; CHECK: FUNCTION: main +; CHECK: LINE: {{.+}}basic_var.hlsl:7 +; CHECK: LINE: {{.+}}basic_var.hlsl:11 +; CHECK: VAR: dtid: uint3 : reg{{.+}}, piece 4 +; CHECK: LINE: {{.+}}basic_var.hlsl:17 +; CHECK: VAR: dtid: uint3 : reg{{.+}}, piece 4 +; CHECK: LINE: {{.+}}basic_var.hlsl:11 +; CHECK: VAR: dtid: uint3 : reg{{.+}}, piece 4 +; CHECK: LINE: {{.+}}basic_var.hlsl:14 +; CHECK-DAG: VAR: dtid: uint3 : reg{{.+}}, piece 4 +; CHECK: LINE: {{.+}}basic_var.hlsl:17 +; CHECK-DAG: VAR: dtid: uint3 : reg{{.+}}, piece 4 +; CHECK-DAG: VAR: my_var2: float : reg{{.+}} +; CHECK: LINE: {{.+}}basic_var.hlsl:19 +; CHECK-DAG: VAR: dtid: uint3 : reg{{.+}}, piece 4 +; CHECK-DAG: VAR: my_var2: float : reg{{.+}} + +source_filename = "module" +target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-p10:32:32-p11:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9-p32:32:32-v8:8-v16:16-v32:32-v48:32-v64:32-v80:32-v96:32-v112:32-v128:32-v144:32-v160:32-v176:32-v192:32-v208:32-v224:32-v240:32-v256:32-i1:32-i8:8-i16:16-i32:32-i64:32-f16:16-f32:32-f64:32" +target triple = "amdgcn-amd-amdpal" + +%dx.types.ResRet.f32 = type { float, float, float, float, i32 } + +; Function Attrs: memory(readwrite) +define dllexport amdgpu_cs void @_amdgpu_cs_main(i32 inreg noundef %globalTable, i32 inreg noundef %userdata4, <3 x i32> inreg noundef %WorkgroupId, i32 inreg noundef %MultiDispatchInfo, <3 x i32> noundef %LocalInvocationId) #0 !dbg !14 { + %LocalInvocationId.i0 = extractelement <3 x i32> %LocalInvocationId, i64 0, !dbg !28 + %WorkgroupId.i0 = extractelement <3 x i32> %WorkgroupId, i64 0, !dbg !28 + %1 = call i64 @llvm.amdgcn.s.getpc(), !dbg !28 + %2 = shl i32 %WorkgroupId.i0, 6, !dbg !28 + %3 = add i32 %LocalInvocationId.i0, %2, !dbg !28 + #dbg_value(i32 %3, !29, !DIExpression(DW_OP_LLVM_fragment, 0, 32), !28) + %4 = and i64 %1, -4294967296, !dbg !30 + %5 = zext i32 %userdata4 to i64, !dbg !30 + %6 = or disjoint i64 %4, %5, !dbg !30 + %7 = inttoptr i64 %6 to ptr addrspace(4), !dbg !30 + call void @llvm.assume(i1 true) [ "align"(ptr addrspace(4) %7, i32 4), "dereferenceable"(ptr addrspace(4) %7, i32 -1) ], !dbg !30 + %8 = load <4 x i32>, ptr addrspace(4) %7, align 4, !dbg !30, !invariant.load !2 + %9 = call float @llvm.amdgcn.struct.buffer.load.format.f32(<4 x i32> %8, i32 %3, i32 0, i32 0, i32 0), !dbg !30 + #dbg_value(%dx.types.ResRet.f32 poison, !31, !DIExpression(), !32) + %10 = fmul reassoc arcp contract afn float %9, 2.000000e+00, !dbg !33 + #dbg_value(float %10, !34, !DIExpression(), !35) + call void @llvm.assume(i1 true) [ "align"(ptr addrspace(4) %7, i32 4), "dereferenceable"(ptr addrspace(4) %7, i32 -1) ], !dbg !36 + %11 = getelementptr i8, ptr addrspace(4) %7, i64 32, !dbg !36 + %.upto01 = insertelement <4 x float> poison, float %10, i64 0, !dbg !36 + %12 = shufflevector <4 x float> %.upto01, <4 x float> poison, <4 x i32> zeroinitializer, !dbg !36 + %13 = load <4 x i32>, ptr addrspace(4) %11, align 4, !dbg !36, !invariant.load !2 + call void @llvm.amdgcn.struct.buffer.store.format.v4f32(<4 x float> %12, <4 x i32> %13, i32 %3, i32 0, i32 0, i32 0), !dbg !36 + ret void, !dbg !37 +} + +; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) +declare noundef i64 @llvm.amdgcn.s.getpc() #1 + +; Function Attrs: nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) +declare void @llvm.assume(i1 noundef) #2 + +; Function Attrs: nocallback nofree nosync nounwind willreturn memory(write) +declare void @llvm.amdgcn.struct.buffer.store.format.v4f32(<4 x float>, <4 x i32>, i32, i32, i32, i32 immarg) #3 + +; Function Attrs: nocallback nofree nosync nounwind willreturn memory(read) +declare float @llvm.amdgcn.struct.buffer.load.format.f32(<4 x i32>, i32, i32, i32, i32 immarg) #4 + +attributes #0 = { memory(readwrite) "amdgpu-flat-work-group-size"="64,64" "amdgpu-memory-bound"="false" "amdgpu-num-sgpr"="4294967295" "amdgpu-num-vgpr"="4294967295" "amdgpu-prealloc-sgpr-spill-vgprs" "amdgpu-unroll-threshold"="1200" "amdgpu-wave-limiter"="false" "amdgpu-work-group-info-arg-no"="3" "denormal-fp-math"="ieee" "denormal-fp-math-f32"="preserve-sign" "target-features"=",+wavefrontsize64,+cumode,+enable-flat-scratch" } +attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } +attributes #2 = { nocallback nofree nosync nounwind willreturn memory(inaccessiblemem: write) } +attributes #3 = { nocallback nofree nosync nounwind willreturn memory(write) } +attributes #4 = { nocallback nofree nosync nounwind willreturn memory(read) } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!12, !13} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "dxcoob 1.7.2308.16 (52da17e29)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !3) +!1 = !DIFile(filename: "tests\\basic_var.hlsl", directory: "") +!2 = !{} +!3 = !{!4, !10} +!4 = distinct !DIGlobalVariableExpression(var: !5, expr: !DIExpression()) +!5 = !DIGlobalVariable(name: "u0", linkageName: "\01?u0@@3V?$RWBuffer@M@@A", scope: !0, file: !1, line: 2, type: !6, isLocal: false, isDefinition: true) +!6 = !DICompositeType(tag: DW_TAG_class_type, name: "RWBuffer", file: !1, line: 2, size: 32, align: 32, elements: !2, templateParams: !7) +!7 = !{!8} +!8 = !DITemplateTypeParameter(name: "element", type: !9) +!9 = !DIBasicType(name: "float", size: 32, align: 32, encoding: DW_ATE_float) +!10 = distinct !DIGlobalVariableExpression(var: !11, expr: !DIExpression()) +!11 = !DIGlobalVariable(name: "u1", linkageName: "\01?u1@@3V?$RWBuffer@M@@A", scope: !0, file: !1, line: 3, type: !6, isLocal: false, isDefinition: true) +!12 = !{i32 2, !"Dwarf Version", i32 5} +!13 = !{i32 2, !"Debug Info Version", i32 3} +!14 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 7, type: !15, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0) +!15 = !DISubroutineType(types: !16) +!16 = !{null, !17} +!17 = !DIDerivedType(tag: DW_TAG_typedef, name: "uint3", file: !1, baseType: !18) +!18 = !DICompositeType(tag: DW_TAG_class_type, name: "vector", file: !1, size: 96, align: 32, elements: !19, templateParams: !24) +!19 = !{!20, !22, !23} +!20 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !18, file: !1, baseType: !21, size: 32, align: 32, flags: DIFlagPublic) +!21 = !DIBasicType(name: "unsigned int", size: 32, align: 32, encoding: DW_ATE_unsigned) +!22 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !18, file: !1, baseType: !21, size: 32, align: 32, offset: 32, flags: DIFlagPublic) +!23 = !DIDerivedType(tag: DW_TAG_member, name: "z", scope: !18, file: !1, baseType: !21, size: 32, align: 32, offset: 64, flags: DIFlagPublic) +!24 = !{!25, !26} +!25 = !DITemplateTypeParameter(name: "element", type: !21) +!26 = !DITemplateValueParameter(name: "element_count", type: !27, value: i32 3) +!27 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!28 = !DILocation(line: 7, column: 17, scope: !14) +!29 = !DILocalVariable(name: "dtid", arg: 1, scope: !14, file: !1, line: 7, type: !17) +!30 = !DILocation(line: 11, column: 18, scope: !14) +!31 = !DILocalVariable(name: "my_var", scope: !14, file: !1, line: 11, type: !9) +!32 = !DILocation(line: 11, column: 9, scope: !14) +!33 = !DILocation(line: 14, column: 26, scope: !14) +!34 = !DILocalVariable(name: "my_var2", scope: !14, file: !1, line: 14, type: !9) +!35 = !DILocation(line: 14, column: 9, scope: !14) +!36 = !DILocation(line: 17, column: 14, scope: !14) +!37 = !DILocation(line: 19, column: 1, scope: !14) diff --git a/llvm/test/CodeGen/AMDGPU/amdgpu-reloc-const.ll b/llvm/test/CodeGen/AMDGPU/amdgpu-reloc-const.ll index 1af5938a5d48f..7f9587567a371 100644 --- a/llvm/test/CodeGen/AMDGPU/amdgpu-reloc-const.ll +++ b/llvm/test/CodeGen/AMDGPU/amdgpu-reloc-const.ll @@ -11,8 +11,8 @@ ; GCN-NEXT: .Lfunc_end ; ELF: Relocations [ -; ELF-NEXT: Section (3) .rel.text { -; ELF-NEXT: 0x{{[0-9]+}} R_AMDGPU_ABS32_LO doff_0_0_b{{$}} +; ELF-NEXT: Section (3) .rela.text { +; ELF-NEXT: 0x{{[0-9]+}} R_AMDGPU_ABS32_LO doff_0_0_b 0x0 define amdgpu_ps void @ps_main(i32 %arg, i32 inreg %arg1, i32 inreg %arg2) local_unnamed_addr #0 { %rc = call i32 @llvm.amdgcn.reloc.constant(metadata !1) diff --git a/llvm/test/lit.cfg.py b/llvm/test/lit.cfg.py index bd6e37c848d8c..4e51a52cbded6 100644 --- a/llvm/test/lit.cfg.py +++ b/llvm/test/lit.cfg.py @@ -189,6 +189,7 @@ def get_asan_rtlib(): "llvm-cvtres", "llvm-debuginfod-find", "llvm-debuginfo-analyzer", + "llvm-debuginfo-check", "llvm-diff", "llvm-dis", "llvm-dwarfdump", diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-print-basic-details.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-print-basic-details.test index 54dbd7466e4f6..6d767eb9e883a 100644 --- a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-print-basic-details.test +++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-print-basic-details.test @@ -45,8 +45,6 @@ ; ONE-NEXT: [004] 6 {Line} ; ONE-NEXT: [004] {Code} 'movl $0x7, -0x4(%rbp)' ; ONE-NEXT: [004] {Code} 'jmp 0x6' -; ONE-NEXT: [004] 8 {Line} -; ONE-NEXT: [004] {Code} 'movl -0x14(%rbp), %eax' ; ONE-NEXT: [003] 4 {TypeAlias} 'INTEGER' -> 'int' ; ONE-NEXT: [003] 2 {Line} ; ONE-NEXT: [003] {Code} 'pushq %rbp' @@ -60,10 +58,12 @@ ; ONE-NEXT: [003] {Code} 'testb $0x1, -0x15(%rbp)' ; ONE-NEXT: [003] {Code} 'je 0x13' ; ONE-NEXT: [003] 8 {Line} +; ONE-NEXT: [003] {Code} 'movl -0x14(%rbp), %eax' +; ONE-NEXT: [003] 8 {Line} ; ONE-NEXT: [003] {Code} 'movl %eax, -0x4(%rbp)' ; ONE-NEXT: [003] 9 {Line} ; ONE-NEXT: [003] {Code} 'movl -0x4(%rbp), %eax' ; ONE-NEXT: [003] {Code} 'popq %rbp' ; ONE-NEXT: [003] {Code} 'retq' -; ONE-NEXT: [003] 9 {Line} ; ONE-NEXT: [002] 1 {TypeAlias} 'INTPTR' -> '* const int' +; ONE-NEXT: [002] 9 {Line} diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-select-logical-elements.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-select-logical-elements.test index f84e9201d3044..5690cf585c379 100644 --- a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-select-logical-elements.test +++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-select-logical-elements.test @@ -34,7 +34,7 @@ ; ONE-NEXT: [004] {Code} 'movl $0x7, -0x4(%rbp)' ; ONE-NEXT: [003] {Code} 'movl %eax, -0x4(%rbp)' ; ONE-NEXT: [003] {Code} 'movl %esi, -0x14(%rbp)' -; ONE-NEXT: [004] {Code} 'movl -0x14(%rbp), %eax' +; ONE-NEXT: [003] {Code} 'movl -0x14(%rbp), %eax' ; ONE-NEXT: [003] {Code} 'movl -0x4(%rbp), %eax' ; ONE-NEXT: [003] 4 {TypeAlias} 'INTEGER' -> 'int' ; ONE-NEXT: [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER' diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/02-dwarf-logical-lines.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/02-dwarf-logical-lines.test index 533914f002827..bff7c945b6eac 100644 --- a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/02-dwarf-logical-lines.test +++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/02-dwarf-logical-lines.test @@ -42,7 +42,7 @@ ; ONE-NEXT: [003] {Code} 'addq $0x10, %rsp' ; ONE-NEXT: [003] {Code} 'popq %rbp' ; ONE-NEXT: [003] {Code} 'retq' -; ONE-NEXT: [003] 6 {Line} +; ONE-NEXT: [002] 6 {Line} ; ONE-EMPTY: ; ONE-NEXT: Logical View: ; ONE-NEXT: [000] {File} 'hello-world-dwarf-gcc.o' -> elf64-x86-64 @@ -64,4 +64,4 @@ ; ONE-NEXT: [003] 7 {Line} ; ONE-NEXT: [003] {Code} 'popq %rbp' ; ONE-NEXT: [003] {Code} 'retq' -; ONE-NEXT: [003] 7 {Line} +; ONE-NEXT: [002] 7 {Line} diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/03-dwarf-incorrect-lexical-scope-typedef.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/03-dwarf-incorrect-lexical-scope-typedef.test index dc57d01f3b8bb..69b65148361d7 100644 --- a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/03-dwarf-incorrect-lexical-scope-typedef.test +++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/03-dwarf-incorrect-lexical-scope-typedef.test @@ -59,7 +59,6 @@ ; ONE-NEXT: [004] 10 {Line} ; ONE-NEXT: [004] 10 {Line} ; ONE-NEXT: [004] 10 {Line} -; ONE-NEXT: [004] 13 {Line} ; ONE-NEXT: [003] 3 {Parameter} 'Param' -> 'char' ; ONE-NEXT: [003] 7 {TypeAlias} 'FLOAT' -> 'float' ; ONE-NEXT: [003] 4 {TypeAlias} 'INT' -> 'int' @@ -71,6 +70,7 @@ ; ONE-NEXT: [003] 13 {Line} ; ONE-NEXT: [003] 13 {Line} ; ONE-NEXT: [003] 13 {Line} +; ONE-NEXT: [002] 13 {Line} ; ONE-EMPTY: ; ONE-NEXT: Logical View: ; ONE-NEXT: [000] {File} 'pr-44884-dwarf-gcc.o' -> elf64-x86-64 @@ -91,7 +91,6 @@ ; ONE-NEXT: [005] 9 {Line} ; ONE-NEXT: [005] 9 {Line} ; ONE-NEXT: [005] 10 {Line} -; ONE-NEXT: [005] 13 {Line} ; ONE-NEXT: [004] 7 {TypeAlias} 'FLOAT' -> 'float' ; ONE-NEXT: [003] 3 {Parameter} 'Param' -> 'char' ; ONE-NEXT: [003] 4 {TypeAlias} 'INT' -> 'int' @@ -99,8 +98,9 @@ ; ONE-NEXT: [003] 3 {Line} ; ONE-NEXT: [003] 5 {Line} ; ONE-NEXT: [003] 13 {Line} +; ONE-NEXT: [003] 13 {Line} ; ONE-NEXT: [003] 14 {Line} -; ONE-NEXT: [003] 14 {Line} +; ONE-NEXT: [002] 14 {Line} ; Using the selection facilities, we can produce a simple tabular ; output showing just the logical types that are 'Typedef'. diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/06-dwarf-full-logical-view.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/06-dwarf-full-logical-view.test index 6616710a10045..a2f05ddb3e6ec 100644 --- a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/06-dwarf-full-logical-view.test +++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/06-dwarf-full-logical-view.test @@ -53,8 +53,6 @@ ; ONE-NEXT: [0x0000000023][004] 6 {Line} {NewStatement} '/data/projects/tests/input/general/test.cpp' ; ONE-NEXT: [0x0000000023][004] {Code} 'movl $0x7, -0x4(%rbp)' ; ONE-NEXT: [0x000000002a][004] {Code} 'jmp 0x6' -; ONE-NEXT: [0x000000002f][004] 8 {Line} {NewStatement} '/data/projects/tests/input/general/test.cpp' -; ONE-NEXT: [0x000000002f][004] {Code} 'movl -0x14(%rbp), %eax' ; ONE-NEXT: [0x0000000063][003] 2 {Parameter} 'ParamBool' -> [0x00000000bc]'bool' ; ONE-NEXT: [0x0000000063][004] {Coverage} 100.00% ; ONE-NEXT: [0x0000000064][004] {Location} @@ -79,13 +77,15 @@ ; ONE-NEXT: [0x0000000012][003] 3 {Line} {NewStatement} {PrologueEnd} '/data/projects/tests/input/general/test.cpp' ; ONE-NEXT: [0x0000000012][003] {Code} 'testb $0x1, -0x15(%rbp)' ; ONE-NEXT: [0x0000000016][003] {Code} 'je 0x13' +; ONE-NEXT: [0x000000002f][003] 8 {Line} {NewStatement} '/data/projects/tests/input/general/test.cpp' +; ONE-NEXT: [0x000000002f][003] {Code} 'movl -0x14(%rbp), %eax' ; ONE-NEXT: [0x0000000032][003] 8 {Line} '/data/projects/tests/input/general/test.cpp' ; ONE-NEXT: [0x0000000032][003] {Code} 'movl %eax, -0x4(%rbp)' ; ONE-NEXT: [0x0000000035][003] 9 {Line} {NewStatement} '/data/projects/tests/input/general/test.cpp' ; ONE-NEXT: [0x0000000035][003] {Code} 'movl -0x4(%rbp), %eax' ; ONE-NEXT: [0x0000000038][003] {Code} 'popq %rbp' ; ONE-NEXT: [0x0000000039][003] {Code} 'retq' -; ONE-NEXT: [0x000000003a][003] 9 {Line} {NewStatement} {EndSequence} '/data/projects/tests/input/general/test.cpp' +; ONE-NEXT: [0x000000003a][002] 9 {Line} {NewStatement} {EndSequence} '/data/projects/tests/input/general/test.cpp' ; ONE-EMPTY: ; ONE-NEXT: ----------------------------- ; ONE-NEXT: Element Total Printed diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-incorrect-logical-instructions.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-incorrect-logical-instructions.test index a99eae2aa2933..b38db28085b3e 100644 --- a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-incorrect-logical-instructions.test +++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-incorrect-logical-instructions.test @@ -84,7 +84,6 @@ ; ONE-NEXT: [003] {Code} 'addq $0x10, %rsp' ; ONE-NEXT: [003] {Code} 'popq %rbp' ; ONE-NEXT: [003] {Code} 'retq' -; ONE-NEXT: [003] {Code} 'data16' ; ONE-NEXT: [002] 10 {Function} extern not_inlined 'test' -> 'int' ; ONE-NEXT: [003] {Block} ; ONE-NEXT: [004] 13 {Line} @@ -106,8 +105,6 @@ ; ONE-NEXT: [004] {Code} 'movl -0x8(%rbp), %eax' ; ONE-NEXT: [004] {Code} 'addl $0x1, %eax' ; ONE-NEXT: [004] {Code} 'movl %eax, -0x8(%rbp)' -; ONE-NEXT: [004] 17 {Line} -; ONE-NEXT: [004] {Code} 'movl -0x8(%rbp), %eax' ; ONE-NEXT: [003] 10 {Line} ; ONE-NEXT: [003] {Code} 'pushq %rbp' ; ONE-NEXT: [003] {Code} 'movq %rsp, %rbp' @@ -120,6 +117,8 @@ ; ONE-NEXT: [003] 11 {Line} ; ONE-NEXT: [003] {Code} 'movl %eax, -0x8(%rbp)' ; ONE-NEXT: [003] 17 {Line} +; ONE-NEXT: [003] {Code} 'movl -0x8(%rbp), %eax' +; ONE-NEXT: [003] 17 {Line} ; ONE-NEXT: [003] {Code} 'addq $0x10, %rsp' ; ONE-NEXT: [003] {Code} 'popq %rbp' ; ONE-NEXT: [003] {Code} 'retq' @@ -132,7 +131,8 @@ ; ONE-NEXT: [003] {Code} 'xorl %eax, %eax' ; ONE-NEXT: [003] {Code} 'popq %rbp' ; ONE-NEXT: [003] {Code} 'retq' -; ONE-NEXT: [003] 21 {Line} +; ONE-NEXT: [002] {Code} 'data16' +; ONE-NEXT: [002] 21 {Line} ; RUN: llvm-debuginfo-analyzer --attribute=level \ ; RUN: --print=instructions \ @@ -172,7 +172,6 @@ ; TWO-NEXT: [003] {Code} 'addq $0x10, %rsp' ; TWO-NEXT: [003] {Code} 'popq %rbp' ; TWO-NEXT: [003] {Code} 'retq' -; TWO-NEXT: [003] {Code} 'data16' ; TWO-NEXT: [002] 10 {Function} extern not_inlined 'test' -> 'int' ; TWO-NEXT: [003] {Block} ; TWO-NEXT: [004] {Code} 'movl $0x0, -0xc(%rbp)' @@ -187,7 +186,6 @@ ; TWO-NEXT: [004] {Code} 'movl -0x8(%rbp), %eax' ; TWO-NEXT: [004] {Code} 'addl $0x1, %eax' ; TWO-NEXT: [004] {Code} 'movl %eax, -0x8(%rbp)' -; TWO-NEXT: [004] {Code} 'movl -0x8(%rbp), %eax' ; TWO-NEXT: [003] {Code} 'pushq %rbp' ; TWO-NEXT: [003] {Code} 'movq %rsp, %rbp' ; TWO-NEXT: [003] {Code} 'subq $0x10, %rsp' @@ -195,6 +193,7 @@ ; TWO-NEXT: [003] {Code} 'movl -0x4(%rbp), %eax' ; TWO-NEXT: [003] {Code} 'subl (%rip), %eax' ; TWO-NEXT: [003] {Code} 'movl %eax, -0x8(%rbp)' +; TWO-NEXT: [003] {Code} 'movl -0x8(%rbp), %eax' ; TWO-NEXT: [003] {Code} 'addq $0x10, %rsp' ; TWO-NEXT: [003] {Code} 'popq %rbp' ; TWO-NEXT: [003] {Code} 'retq' diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/01-wasm-print-basic-details.test b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/01-wasm-print-basic-details.test index 4927086563330..183e3ddc75ca1 100644 --- a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/01-wasm-print-basic-details.test +++ b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/01-wasm-print-basic-details.test @@ -56,8 +56,6 @@ ; ONE-NEXT: [004] {Code} 'local.get 11' ; ONE-NEXT: [004] {Code} 'i32.store 28' ; ONE-NEXT: [004] {Code} 'br 1' -; ONE-NEXT: [004] - {Line} -; ONE-NEXT: [004] {Code} 'end' ; ONE-NEXT: [003] 4 {TypeAlias} 'INTEGER' -> 'int' ; ONE-NEXT: [003] 2 {Line} ; ONE-NEXT: [003] {Code} 'nop' @@ -98,6 +96,8 @@ ; ONE-NEXT: [003] {Code} 'local.get 9' ; ONE-NEXT: [003] {Code} 'i32.eqz' ; ONE-NEXT: [003] {Code} 'br_if 0' +; ONE-NEXT: [003] - {Line} +; ONE-NEXT: [003] {Code} 'end' ; ONE-NEXT: [003] 8 {Line} ; ONE-NEXT: [003] {Code} 'local.get 5' ; ONE-NEXT: [003] {Code} 'i32.load 20' @@ -115,6 +115,6 @@ ; ONE-NEXT: [003] {Code} 'local.get 13' ; ONE-NEXT: [003] {Code} 'return' ; ONE-NEXT: [003] {Code} 'end' -; ONE-NEXT: [003] 9 {Line} -; ONE-NEXT: [003] {Code} 'unreachable' ; ONE-NEXT: [002] 1 {TypeAlias} 'INTPTR' -> '* const int' +; ONE-NEXT: [002] 9 {Line} +; ONE-NEXT: [002] {Code} 'unreachable' diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/02-wasm-logical-lines.test b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/02-wasm-logical-lines.test index 50a531ad7d823..8d764648bdd5a 100644 --- a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/02-wasm-logical-lines.test +++ b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/02-wasm-logical-lines.test @@ -71,5 +71,5 @@ ; ONE-NEXT: [003] {Code} 'local.get 6' ; ONE-NEXT: [003] {Code} 'return' ; ONE-NEXT: [003] {Code} 'end' -; ONE-NEXT: [003] 6 {Line} -; ONE-NEXT: [003] {Code} 'return' +; ONE-NEXT: [002] 6 {Line} +; ONE-NEXT: [002] {Code} 'return' diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/03-wasm-incorrect-lexical-scope-typedef.test b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/03-wasm-incorrect-lexical-scope-typedef.test index 1192a0cb7ca5a..a89d49abd6280 100644 --- a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/03-wasm-incorrect-lexical-scope-typedef.test +++ b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/03-wasm-incorrect-lexical-scope-typedef.test @@ -55,7 +55,6 @@ ; ONE-NEXT: [003] - {Line} ; ONE-NEXT: [003] 1 {Line} ; ONE-NEXT: [003] 1 {Line} -; ONE-NEXT: [003] 1 {Line} ; ONE-NEXT: [002] 3 {Function} extern not_inlined 'foo' -> 'unsigned int' ; ONE-NEXT: [003] {Block} ; ONE-NEXT: [004] 9 {Variable} 'Added' -> 'FLOAT' @@ -67,7 +66,6 @@ ; ONE-NEXT: [004] 10 {Line} ; ONE-NEXT: [004] 10 {Line} ; ONE-NEXT: [004] 10 {Line} -; ONE-NEXT: [004] 13 {Line} ; ONE-NEXT: [003] 3 {Parameter} 'Param' -> 'char' ; ONE-NEXT: [003] 7 {TypeAlias} 'FLOAT' -> 'float' ; ONE-NEXT: [003] 4 {TypeAlias} 'INT' -> 'int' @@ -79,6 +77,8 @@ ; ONE-NEXT: [003] 13 {Line} ; ONE-NEXT: [003] 13 {Line} ; ONE-NEXT: [003] 13 {Line} +; ONE-NEXT: [002] 1 {Line} +; ONE-NEXT: [002] 13 {Line} ; ONE-EMPTY: ; ONE-NEXT: Logical View: ; ONE-NEXT: [000] {File} 'pr-44884-dwarf-gcc.o' -> elf64-x86-64 @@ -99,7 +99,6 @@ ; ONE-NEXT: [005] 9 {Line} ; ONE-NEXT: [005] 9 {Line} ; ONE-NEXT: [005] 10 {Line} -; ONE-NEXT: [005] 13 {Line} ; ONE-NEXT: [004] 7 {TypeAlias} 'FLOAT' -> 'float' ; ONE-NEXT: [003] 3 {Parameter} 'Param' -> 'char' ; ONE-NEXT: [003] 4 {TypeAlias} 'INT' -> 'int' @@ -107,8 +106,9 @@ ; ONE-NEXT: [003] 3 {Line} ; ONE-NEXT: [003] 5 {Line} ; ONE-NEXT: [003] 13 {Line} +; ONE-NEXT: [003] 13 {Line} ; ONE-NEXT: [003] 14 {Line} -; ONE-NEXT: [003] 14 {Line} +; ONE-NEXT: [002] 14 {Line} ; Using the selection facilities, we can produce a simple tabular ; output showing just the logical types that are 'Typedef'. diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/06-wasm-full-logical-view.test b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/06-wasm-full-logical-view.test index ac4873f0a4d34..e152f40d99213 100644 --- a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/06-wasm-full-logical-view.test +++ b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/06-wasm-full-logical-view.test @@ -64,8 +64,6 @@ ; ONE-NEXT: [0x000000005d][004] {Code} 'local.get 11' ; ONE-NEXT: [0x000000005f][004] {Code} 'i32.store 28' ; ONE-NEXT: [0x0000000062][004] {Code} 'br 1' -; ONE-NEXT: [0x0000000064][004] 0 {Line} '{{.*}}/general/test.cpp' -; ONE-NEXT: [0x0000000064][004] {Code} 'end' ; ONE-NEXT: [0x000000005e][003] 2 {Parameter} 'ParamBool' -> [0x00000000b3]'bool' ; ONE-NEXT: [0x000000005e][004] {Coverage} 100.00% ; ONE-NEXT: [0x000000005f][004] {Location} @@ -118,6 +116,8 @@ ; ONE-NEXT: [0x0000000047][003] {Code} 'local.get 9' ; ONE-NEXT: [0x0000000049][003] {Code} 'i32.eqz' ; ONE-NEXT: [0x000000004a][003] {Code} 'br_if 0' +; ONE-NEXT: [0x0000000064][003] 0 {Line} '{{.*}}/general/test.cpp' +; ONE-NEXT: [0x0000000064][003] {Code} 'end' ; ONE-NEXT: [0x0000000065][003] 8 {Line} {NewStatement} '{{.*}}/general/test.cpp' ; ONE-NEXT: [0x0000000065][003] {Code} 'local.get 5' ; ONE-NEXT: [0x0000000067][003] {Code} 'i32.load 20' @@ -135,8 +135,8 @@ ; ONE-NEXT: [0x000000007b][003] {Code} 'local.get 13' ; ONE-NEXT: [0x000000007d][003] {Code} 'return' ; ONE-NEXT: [0x000000007e][003] {Code} 'end' -; ONE-NEXT: [0x000000007f][003] 9 {Line} {NewStatement} {EndSequence} '{{.*}}/general/test.cpp' -; ONE-NEXT: [0x000000007f][003] {Code} 'unreachable' +; ONE-NEXT: [0x000000007f][002] 9 {Line} {NewStatement} {EndSequence} '{{.*}}/general/test.cpp' +; ONE-NEXT: [0x000000007f][002] {Code} 'unreachable' ; ONE-EMPTY: ; ONE-NEXT: ----------------------------- ; ONE-NEXT: Element Total Printed diff --git a/llvm/tools/llvm-debuginfo-check/CMakeLists.txt b/llvm/tools/llvm-debuginfo-check/CMakeLists.txt new file mode 100644 index 0000000000000..4ca37ac8ae856 --- /dev/null +++ b/llvm/tools/llvm-debuginfo-check/CMakeLists.txt @@ -0,0 +1,17 @@ +set(LLVM_LINK_COMPONENTS + AllTargetsDescs + AllTargetsDisassemblers + AllTargetsInfos + BinaryFormat + DebugInfoCodeView + DebugInfoLogicalView + DebugInfoPDB + MC + MCDisassembler + Object + Support + ) + +add_llvm_tool(llvm-debuginfo-check + llvm-debuginfo-check.cpp + ) diff --git a/llvm/tools/llvm-debuginfo-check/llvm-debuginfo-check.cpp b/llvm/tools/llvm-debuginfo-check/llvm-debuginfo-check.cpp new file mode 100644 index 0000000000000..d6ca9f0ee06c9 --- /dev/null +++ b/llvm/tools/llvm-debuginfo-check/llvm-debuginfo-check.cpp @@ -0,0 +1,248 @@ +//===-- llvm-debuginfo-check.cpp - LLVM Debug info analysis utility -------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This tool prints out the logical view of debug info in a way that is easy +// to verify correctness. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SetVector.h" +#include "llvm/DebugInfo/LogicalView/LVReaderHandler.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/TargetSelect.h" + +#include +#include +#include + +constexpr const char *HelpText = + R"(Prints debug info in a way that is easy to verify correctness of debug info. + +FUNCTION: main + LINE: my_source_file.c:1 [main] <---- New statement lines, inlined callstack + VAR: argc : int : {expression} <---- Variables live at this point + VAR: argv : char ** : {expression} + LINE: my_source_file.c:2 [main] + VAR: argc : int + VAR: argv : char ** + LINE: my_source_file.c:3 [main] + VAR: argc : int + VAR: argv : char ** + LINE: my_source_file.c:4 [main] +)"; + +using namespace llvm; +using namespace logicalview; + +static cl::opt + InputFilename(cl::Positional, "", + cl::desc("Input file, an object file with DWARF."), + cl::Required); + +static cl::opt IncludeCode("code", cl::desc("Include asm")); +static cl::opt + IncludeRanges("ranges", cl::desc("Include variable ranges"), cl::Hidden); +static cl::opt IncludeVars("vars", cl::desc("Include live variables")); + +template T Take(Expected ExpectedResult, const Twine &Msg) { + if (!ExpectedResult) { + auto Err = ExpectedResult.takeError(); + errs() << Msg << " " << toStringWithoutConsuming(Err) << '\n'; + exit(2); + } + T ret = std::move(*ExpectedResult); + return ret; +} + +struct ScopePrinter { + std::vector Lines; + std::unordered_map> LivetimeBegins; + std::unordered_map> + LivetimeEndsExclusive; + raw_ostream &OS; + + void Walk(raw_ostream &OS, const LVScope *Scope) { + if (Scope->scopeCount()) { + for (const LVScope *ChildScope : *Scope->getScopes()) + Walk(OS, ChildScope); + } + if (Scope->lineCount()) { + for (const LVLine *Line : *Scope->getLines()) { + Lines.push_back(Line); + } + } + if (Scope->symbolCount()) { + for (const LVSymbol *Symbol : *Scope->getSymbols()) { + LVLocations SymbolLocations; + Symbol->getLocations(SymbolLocations); + if (SymbolLocations.empty()) + continue; + + if (IncludeRanges) { + OS << "RANGES: " << Symbol->getName() << " (line " + << Symbol->getLineNumber() << ")" << ": "; + } + + for (const LVLocation *Loc : SymbolLocations) { + if (Loc->getIsGapEntry()) + continue; + + LVAddress Begin = Loc->getLowerAddress(); + LVAddress End = Loc->getUpperAddress(); + LivetimeBegins[Begin].push_back(Loc); + LivetimeEndsExclusive[End].push_back(Loc); + if (IncludeRanges) { + OS << "[" << hexValue(Begin) << ":" << hexValue(End) << "] "; + } + } + + if (IncludeRanges) + OS << "\n"; + } + } + } + + ScopePrinter(raw_ostream &OS, const LVScopeFunction *Fn) : OS(OS) { + Walk(OS, Fn); + std::sort(Lines.begin(), Lines.end(), + [](const LVLine *a, const LVLine *b) -> bool { + if (a->getAddress() != b->getAddress()) + return a->getAddress() < b->getAddress(); + if (a->getIsLineDebug() != b->getIsLineDebug()) + return a->getIsLineDebug(); + return a->getID() < b->getID(); + }); + } + + static void PrintIndent(raw_ostream &OS, int Indent) { + for (int i = 0; i < Indent; i++) + OS << " "; + } + + static void PrintCallstack(raw_ostream &OS, const LVScope *Scope) { + bool First = true; + const LVScope *PrevScope = nullptr; + while (Scope) { + if (Scope->getIsFunction() || Scope->getIsInlinedFunction()) { + OS << "[" << Scope->getName(); + if (PrevScope && PrevScope->getIsInlinedFunction()) { + OS << ":" + << cast(PrevScope)->getCallLineNumber(); + } + OS << "]"; + First = false; + PrevScope = Scope; + } + Scope = Scope->getParentScope(); + } + } + + static bool IsChildScopeOf(const LVScope *A, const LVScope *B) { + while (A) { + A = A->getParentScope(); + if (A == B) + return true; + } + return false; + } + + void Print() { + SetVector + LiveSymbols; // This needs to be ordered since we're iterating over it. + for (const LVLine *Line : Lines) { + + const LVScope *Scope = Line->getParentScope(); + + // Update live list: Add lives + for (auto Loc : LivetimeBegins[Line->getAddress()]) + LiveSymbols.insert(Loc); + // Update live list: remove dead + for (auto Loc : LivetimeEndsExclusive[Line->getAddress()]) + LiveSymbols.remove(Loc); + + if (Line->getIsNewStatement() && Line->getIsLineDebug() && + Line->getLineNumber() != 0) { + auto LineDebug = cast(Line); + + OS << "LINE: " << " [" << hexValue(LineDebug->getAddress()) << "] " + << LineDebug->getPathname() << ":" << LineDebug->getLineNumber() + << " "; + PrintCallstack(OS, Scope); + OS << "\n"; + if (IncludeVars) { + for (auto SymLoc : LiveSymbols) { + const LVSymbol *Sym = SymLoc->getParentSymbol(); + auto SymScope = Sym->getParentScope(); + auto LineScope = LineDebug->getParentScope(); + if (SymScope != LineScope && !IsChildScopeOf(LineScope, SymScope)) + continue; + PrintIndent(OS, 1); + OS << "VAR: " << Sym->getName() << ": " << Sym->getType()->getName() + << " : "; + SymLoc->printLocations(OS); + OS << " (line " << Sym->getLineNumber() << ")"; + OS << "\n"; + } + } + + } else if (IncludeCode && Line->getIsLineAssembler()) { + OS << " CODE: " << " [" << hexValue(Line->getAddress()) << "] " + << Line->getName() << "\n"; + } + } + } +}; + +int main(int argc, char *argv[]) { + InitLLVM X(argc, argv); + + // Initialize targets and assembly printers/parsers. + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargetMCs(); + InitializeAllDisassemblers(); + + cl::ParseCommandLineOptions(argc, argv, HelpText); + + ScopedPrinter W(llvm::outs()); + LVOptions Options; + Options.setAttributeAll(); + Options.setAttributeAnyLocation(); + Options.setPrintAll(); + Options.setPrintAnyLine(); + Options.resolveDependencies(); + std::vector Objects; + LVReaderHandler Handler(Objects, W, Options); + auto Readers = Take(Handler.createReader(InputFilename), + Twine("Failed to create LV reader from '") + + Twine(InputFilename) + Twine("'")); + + auto *CU = Readers->getCompileUnit(); + if (!CU) { + errs() << "No compute unit found.\n"; + return 2; + } + + for (LVElement *Child : *CU->getChildren()) { + auto *Fn = dyn_cast(Child); + if (Fn) { + const LVLines *Lines = Fn->getLines(); + // If there's no lines, this function has no body. + if (!Lines) + continue; + outs() << "FUNCTION: " << Child->getName() << "\n"; + + ScopePrinter P(outs(), Fn); + P.Print(); + } + } + + return EXIT_SUCCESS; +} diff --git a/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp b/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp index 544c39a3c7b2e..78dc8502e9676 100644 --- a/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp +++ b/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp @@ -81,7 +81,7 @@ void checkElementProperties(LVReader *Reader) { EXPECT_EQ(Language, LVSourceLanguage::DW_LANG_C_plus_plus_14); EXPECT_EQ(Language.getName(), "DW_LANG_C_plus_plus_14"); - EXPECT_EQ(CompileUnit->lineCount(), 0u); + EXPECT_EQ(CompileUnit->lineCount(), 1u); EXPECT_EQ(CompileUnit->scopeCount(), 1u); EXPECT_EQ(CompileUnit->symbolCount(), 0u); EXPECT_EQ(CompileUnit->typeCount(), 7u); @@ -129,7 +129,7 @@ void checkElementProperties(LVReader *Reader) { // Lines (debug and assembler) for 'foo'. const LVLines *Lines = Function->getLines(); ASSERT_NE(Lines, nullptr); - ASSERT_EQ(Lines->size(), 0x12u); + ASSERT_EQ(Lines->size(), 19u); // Check size of types in CompileUnit. const LVTypes *Types = CompileUnit->getTypes(); @@ -252,7 +252,7 @@ void checkElementComparison(LVReader *Reference, LVReader *Target) { // Get comparison table. LVPassTable PassTable = Compare.getPassTable(); - ASSERT_EQ(PassTable.size(), 5u); + ASSERT_EQ(PassTable.size(), 4u); LVReader *Reader; LVElement *Element; @@ -278,18 +278,8 @@ void checkElementComparison(LVReader *Reference, LVReader *Target) { EXPECT_EQ(Element->getName(), "INTEGER"); EXPECT_EQ(Pass, LVComparePass::Missing); - // Reference: Missing DebugLine - std::tie(Reader, Element, Pass) = PassTable[2]; - ASSERT_NE(Reader, nullptr); - ASSERT_NE(Element, nullptr); - EXPECT_EQ(Reader, Reference); - EXPECT_EQ(Element->getLevel(), 3u); - EXPECT_EQ(Element->getLineNumber(), 8u); - EXPECT_EQ(Element->getName(), ""); - EXPECT_EQ(Pass, LVComparePass::Missing); - // Target: Added Variable 'CONSTANT' - std::tie(Reader, Element, Pass) = PassTable[3]; + std::tie(Reader, Element, Pass) = PassTable[2]; ASSERT_NE(Reader, nullptr); ASSERT_NE(Element, nullptr); EXPECT_EQ(Reader, Target); @@ -299,7 +289,7 @@ void checkElementComparison(LVReader *Reference, LVReader *Target) { EXPECT_EQ(Pass, LVComparePass::Added); // Target: Added TypeDefinition 'INTEGER' - std::tie(Reader, Element, Pass) = PassTable[4]; + std::tie(Reader, Element, Pass) = PassTable[3]; ASSERT_NE(Reader, nullptr); ASSERT_NE(Element, nullptr); EXPECT_EQ(Reader, Target);