diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h @@ -375,6 +375,23 @@ static bool isAddressSizeSupported(unsigned AddressSize) { return llvm::is_contained(getSupportedAddressSizes(), AddressSize); } + template + static Error checkAddressSizeSupported(unsigned AddressSize, + std::error_code EC, char const *Fmt, + const Ts &...Vals) { + if (isAddressSizeSupported(AddressSize)) + return Error::success(); + std::string Buffer; + raw_string_ostream Stream(Buffer); + Stream << format(Fmt, Vals...) + << " has unsupported address size: " << AddressSize + << " (supported are "; + ListSeparator LS; + for (unsigned Size : DWARFContext::getSupportedAddressSizes()) + Stream << LS << Size; + Stream << ')'; + return make_error(Stream.str(), EC); + } std::shared_ptr getDWOContext(StringRef AbsolutePath); diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h @@ -49,12 +49,7 @@ /// 2. An address, which defines the appropriate base address for /// use in interpreting the beginning and ending address offsets of /// subsequent entries of the location list. - bool isBaseAddressSelectionEntry(uint8_t AddressSize) const { - assert(AddressSize == 4 || AddressSize == 8); - if (AddressSize == 4) - return StartAddress == -1U; - return StartAddress == -1ULL; - } + bool isBaseAddressSelectionEntry(uint8_t AddressSize) const; }; private: diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp @@ -8,7 +8,7 @@ #include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h" #include "llvm/BinaryFormat/Dwarf.h" -#include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" using namespace llvm; @@ -18,12 +18,10 @@ assert(EndOffset >= *OffsetPtr); uint64_t DataSize = EndOffset - *OffsetPtr; assert(Data.isValidOffsetForDataOfSize(*OffsetPtr, DataSize)); - if (AddrSize != 4 && AddrSize != 8) - return createStringError(errc::not_supported, - "address table at offset 0x%" PRIx64 - " has unsupported address size %" PRIu8 - " (4 and 8 are supported)", - Offset, AddrSize); + if (Error SizeErr = DWARFContext::checkAddressSizeSupported( + AddrSize, errc::not_supported, "address table at offset 0x%" PRIx64, + Offset)) + return SizeErr; if (DataSize % AddrSize != 0) { invalidateLength(); return createStringError(errc::invalid_argument, @@ -148,8 +146,20 @@ } if (Addrs.size() > 0) { - const char *AddrFmt = - (AddrSize == 4) ? "0x%8.8" PRIx64 "\n" : "0x%16.16" PRIx64 "\n"; + const char *AddrFmt; + switch (AddrSize) { + case 2: + AddrFmt = "0x%4.4" PRIx64 "\n"; + break; + case 4: + AddrFmt = "0x%8.8" PRIx64 "\n"; + break; + case 8: + AddrFmt = "0x%16.16" PRIx64 "\n"; + break; + default: + llvm_unreachable("unsupported address size"); + } OS << "Addrs: [\n"; for (uint64_t Addr : Addrs) OS << format(AddrFmt, Addr); diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp @@ -8,6 +8,7 @@ #include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h" #include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/Support/Errc.h" #include "llvm/Support/Format.h" @@ -87,12 +88,10 @@ "the length of address range table at offset " "0x%" PRIx64 " exceeds section size", Offset); - if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8) - return createStringError(errc::invalid_argument, - "address range table at offset 0x%" PRIx64 - " has unsupported address size: %d " - "(4 and 8 supported)", - Offset, HeaderData.AddrSize); + if (Error SizeErr = DWARFContext::checkAddressSizeSupported( + HeaderData.AddrSize, errc::invalid_argument, + "address range table at offset 0x%" PRIx64, Offset)) + return SizeErr; if (HeaderData.SegSize != 0) return createStringError(errc::not_supported, "non-zero segment selector size in address range " diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp @@ -16,6 +16,12 @@ using namespace llvm; +bool DWARFDebugRangeList::RangeListEntry::isBaseAddressSelectionEntry( + uint8_t AddressSize) const { + assert(DWARFContext::isAddressSizeSupported(AddressSize)); + return StartAddress == dwarf::computeTombstoneAddress(AddressSize); +} + void DWARFDebugRangeList::clear() { Offset = -1ULL; AddressSize = 0; @@ -30,9 +36,10 @@ "invalid range list offset 0x%" PRIx64, *offset_ptr); AddressSize = data.getAddressSize(); - if (AddressSize != 4 && AddressSize != 8) - return createStringError(errc::invalid_argument, - "invalid address size: %" PRIu8, AddressSize); + if (Error SizeErr = DWARFContext::checkAddressSizeSupported( + AddressSize, errc::invalid_argument, + "range list at offset 0x%" PRIx64, *offset_ptr)) + return SizeErr; Offset = *offset_ptr; while (true) { RangeListEntry Entry; @@ -58,12 +65,22 @@ } void DWARFDebugRangeList::dump(raw_ostream &OS) const { - for (const RangeListEntry &RLE : Entries) { - const char *format_str = - (AddressSize == 4 ? "%08" PRIx64 " %08" PRIx64 " %08" PRIx64 "\n" - : "%08" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n"); - OS << format(format_str, Offset, RLE.StartAddress, RLE.EndAddress); + const char *AddrFmt; + switch (AddressSize) { + case 2: + AddrFmt = "%08" PRIx64 " %04" PRIx64 " %04" PRIx64 "\n"; + break; + case 4: + AddrFmt = "%08" PRIx64 " %08" PRIx64 " %08" PRIx64 "\n"; + break; + case 8: + AddrFmt = "%08" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n"; + break; + default: + llvm_unreachable("unsupported address size"); } + for (const RangeListEntry &RLE : Entries) + OS << format(AddrFmt, Offset, RLE.StartAddress, RLE.EndAddress); OS << format("%08" PRIx64 " \n", Offset); } diff --git a/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp @@ -8,6 +8,7 @@ #include "llvm/DebugInfo/DWARF/DWARFListTable.h" #include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/Support/Errc.h" #include "llvm/Support/Error.h" #include "llvm/Support/Format.h" @@ -54,11 +55,10 @@ "unrecognised %s table version %" PRIu16 " in table at offset 0x%" PRIx64, SectionName.data(), HeaderData.Version, HeaderOffset); - if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8) - return createStringError(errc::not_supported, - "%s table at offset 0x%" PRIx64 - " has unsupported address size %" PRIu8, - SectionName.data(), HeaderOffset, HeaderData.AddrSize); + if (Error SizeErr = DWARFContext::checkAddressSizeSupported( + HeaderData.AddrSize, errc::not_supported, + "%s table at offset 0x%" PRIx64, SectionName.data(), HeaderOffset)) + return SizeErr; if (HeaderData.SegSize != 0) return createStringError(errc::not_supported, "%s table at offset 0x%" PRIx64 diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -315,15 +315,10 @@ return false; } - if (!DWARFContext::isAddressSizeSupported(getAddressByteSize())) { - SmallVector Sizes; - for (auto Size : DWARFContext::getSupportedAddressSizes()) - Sizes.push_back(std::to_string(Size)); - Context.getWarningHandler()(createStringError( - errc::invalid_argument, - "DWARF unit at offset 0x%8.8" PRIx64 " " - "has unsupported address size %" PRIu8 ", supported are %s", - Offset, getAddressByteSize(), llvm::join(Sizes, ", ").c_str())); + if (Error SizeErr = DWARFContext::checkAddressSizeSupported( + getAddressByteSize(), errc::invalid_argument, + "DWARF unit at offset 0x%8.8" PRIx64, Offset)) { + Context.getWarningHandler()(std::move(SizeErr)); return false; } diff --git a/llvm/test/DebugInfo/MSP430/cu-ranges.ll b/llvm/test/DebugInfo/MSP430/cu-ranges.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/MSP430/cu-ranges.ll @@ -0,0 +1,72 @@ +; RUN: llc -O0 -mtriple=msp430 -filetype=obj %s -o %t +; RUN: llvm-dwarfdump -v %t | FileCheck %s + +; Ported from generic test to cover 2-byte address size case + +; Check that we emit ranges for this which has a non-traditional section and a normal section. + +; CHECK: DW_TAG_compile_unit +; CHECK: DW_AT_ranges +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_low_pc +; CHECK: DW_AT_high_pc +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_low_pc +; CHECK: DW_AT_high_pc + +; CHECK: .debug_ranges contents: +; CHECK-NEXT: 00000000 0000 0030 +; CHECK-NEXT: 00000000 0000 0030 +; CHECK-NEXT: 00000000 + +; Function Attrs: nounwind uwtable +define i32 @foo(i32 %a) #0 section "__TEXT,__foo" !dbg !4 { +entry: + %a.addr = alloca i32, align 4 + store i32 %a, i32* %a.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !13, metadata !DIExpression()), !dbg !14 + %0 = load i32, i32* %a.addr, align 4, !dbg !15 + %add = add nsw i32 %0, 5, !dbg !15 + ret i32 %add, !dbg !15 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: nounwind uwtable +define i32 @bar(i32 %a) #0 !dbg !9 { +entry: + %a.addr = alloca i32, align 4 + store i32 %a, i32* %a.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !16, metadata !DIExpression()), !dbg !17 + %0 = load i32, i32* %a.addr, align 4, !dbg !18 + %add = add nsw i32 %0, 5, !dbg !18 + ret i32 %add, !dbg !18 +} + +attributes #0 = { nounwind uwtable "less-precise-fpmad"="false" "frame-pointer"="all" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!10, !11} +!llvm.ident = !{!12} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.5.0 (trunk 204164) (llvm/trunk 204183)", isOptimized: false, emissionKind: FullDebug, file: !1, enums: !2, retainedTypes: !2, globals: !2, imports: !2) +!1 = !DIFile(filename: "foo.c", directory: "/usr/local/google/home/echristo") +!2 = !{} +!4 = distinct !DISubprogram(name: "foo", line: 1, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 1, file: !1, scope: !5, type: !6, retainedNodes: !2) +!5 = !DIFile(filename: "foo.c", directory: "/usr/local/google/home/echristo") +!6 = !DISubroutineType(types: !7) +!7 = !{!8, !8} +!8 = !DIBasicType(tag: DW_TAG_base_type, name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!9 = distinct !DISubprogram(name: "bar", line: 5, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0, scopeLine: 5, file: !1, scope: !5, type: !6, retainedNodes: !2) +!10 = !{i32 2, !"Dwarf Version", i32 4} +!11 = !{i32 1, !"Debug Info Version", i32 3} +!12 = !{!"clang version 3.5.0 (trunk 204164) (llvm/trunk 204183)"} +!13 = !DILocalVariable(name: "a", line: 1, arg: 1, scope: !4, file: !5, type: !8) +!14 = !DILocation(line: 1, scope: !4) +!15 = !DILocation(line: 2, scope: !4) +!16 = !DILocalVariable(name: "a", line: 5, arg: 1, scope: !9, file: !5, type: !8) +!17 = !DILocation(line: 5, scope: !9) +!18 = !DILocation(line: 6, scope: !9) + diff --git a/llvm/test/DebugInfo/MSP430/dwarf-basics-v5.ll b/llvm/test/DebugInfo/MSP430/dwarf-basics-v5.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/MSP430/dwarf-basics-v5.ll @@ -0,0 +1,154 @@ +; RUN: llc -generate-arange-section -minimize-addr-in-v5=Ranges --filetype=obj -o %t < %s +; RUN: llvm-dwarfdump --debug-info -debug-aranges -debug-addr %t | FileCheck %s +; RUN: llvm-dwarfdump --verify %t + +; This file was based on output of +; +; clang -target msp430 -S -emit-llvm -gdwarf-5 -Os dwarf-basics-v5.c +; +; for the following dwarf-basics-v5.c +; +; struct X { +; void *a; +; }; +; +; int f(long y, struct X *p) +; { +; return 42; +; } +; + +; CHECK: file format elf32-msp430 + +; CHECK: .debug_info contents: +; CHECK: Compile Unit: length = 0x{{.*}}, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0000, addr_size = 0x02 (next unit at 0x{{.*}}) + +; CHECK: DW_TAG_compile_unit +; CHECK: DW_AT_producer ("clang version 14.0.0 (git@...)") +; CHECK: DW_AT_language (DW_LANG_C99) +; CHECK: DW_AT_name ("dwarf-basics-v5.c") +; CHECK: DW_AT_str_offsets_base (0x00000008) +; CHECK: DW_AT_stmt_list (0x{{.*}}) +; CHECK: DW_AT_comp_dir ("/tmp") +; CHECK: DW_AT_low_pc (0x{{.*}}) +; CHECK: DW_AT_high_pc (0x{{.*}}) +; CHECK: DW_AT_addr_base (0x00000008) +; CHECK: DW_AT_loclists_base (0x0000000c) + +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_low_pc (0x{{.*}}) +; CHECK: DW_AT_high_pc (0x{{.*}}) +; CHECK: DW_AT_frame_base (DW_OP_reg1 SPB) +; CHECK: DW_AT_call_all_calls (true) +; CHECK: DW_AT_name ("f") +; CHECK: DW_AT_decl_file ("/tmp{{[/\\]}}dwarf-basics-v5.c") +; CHECK: DW_AT_decl_line (5) +; CHECK: DW_AT_prototyped (true) +; CHECK: DW_AT_type (0x{{.*}} "int") +; CHECK: DW_AT_external (true) + +; CHECK: DW_TAG_formal_parameter +; CHECK: DW_AT_location (indexed (0x0) loclist = 0x{{.*}}: +; CHECK: [0x0000, 0x0004): DW_OP_reg12 R12B) +; CHECK: DW_AT_name ("y") +; CHECK: DW_AT_decl_file ("/tmp{{[/\\]}}dwarf-basics-v5.c") +; CHECK: DW_AT_decl_line (5) +; CHECK: DW_AT_type (0x{{.*}} "long") + +; CHECK: DW_TAG_formal_parameter +; CHECK: DW_AT_location (DW_OP_reg14 R14B) +; CHECK: DW_AT_name ("p") +; CHECK: DW_AT_decl_file ("/tmp{{[/\\]}}dwarf-basics-v5.c") +; CHECK: DW_AT_decl_line (5) +; CHECK: DW_AT_type (0x{{.*}} "X *") + +; CHECK: NULL + +; CHECK: DW_TAG_base_type +; CHECK: DW_AT_name ("int") +; CHECK: DW_AT_encoding (DW_ATE_signed) +; CHECK: DW_AT_byte_size (0x02) + +; CHECK: DW_TAG_base_type +; CHECK: DW_AT_name ("long") +; CHECK: DW_AT_encoding (DW_ATE_signed) +; CHECK: DW_AT_byte_size (0x04) + +; CHECK: DW_TAG_pointer_type +; CHECK: DW_AT_type (0x{{.*}} "X") + +; CHECK: DW_TAG_structure_type +; CHECK: DW_AT_name ("X") +; CHECK: DW_AT_byte_size (0x02) +; CHECK: DW_AT_decl_file ("/tmp{{[/\\]}}dwarf-basics-v5.c") +; CHECK: DW_AT_decl_line (1) + +; CHECK: DW_TAG_member +; CHECK: DW_AT_name ("a") +; CHECK: DW_AT_type (0x{{.*}} "void *") +; CHECK: DW_AT_decl_file ("/tmp{{[/\\]}}dwarf-basics-v5.c") +; CHECK: DW_AT_decl_line (2) +; CHECK: DW_AT_data_member_location (0x00) + +; CHECK: NULL + +; CHECK: DW_TAG_pointer_type + +; CHECK: NULL + +; CHECK: .debug_aranges contents: +; CHECK-NEXT: Address Range Header: length = 0x{{.*}}, format = DWARF32, version = 0x0002, cu_offset = 0x00000000, addr_size = 0x02, seg_size = 0x00 +; CHECK-NEXT: [0x0000, 0x0006) + +; CHECK: .debug_addr contents: +; CHECK-NEXT: Address table header: length = 0x{{.*}}, format = DWARF32, version = 0x0005, addr_size = 0x02, seg_size = 0x00 +; CHECK-NEXT: Addrs: [ +; CHECK-NEXT: 0x0000 +; CHECK-NEXT: ] + +; ModuleID = 'dwarf-basics-v5.c' +source_filename = "dwarf-basics-v5.c" +target datalayout = "e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16" +target triple = "msp430" + +%struct.X = type { i8* } + +; Function Attrs: mustprogress nofree norecurse nosync nounwind optsize readnone willreturn +define dso_local i16 @f(i32 noundef %y, %struct.X* nocapture noundef readnone %p) local_unnamed_addr #0 !dbg !6 { +entry: + call void @llvm.dbg.value(metadata i32 %y, metadata !17, metadata !DIExpression()), !dbg !19 + call void @llvm.dbg.value(metadata %struct.X* %p, metadata !18, metadata !DIExpression()), !dbg !19 + ret i16 42, !dbg !20 +} + +; Function Attrs: nofree nosync nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { mustprogress nofree norecurse nosync nounwind optsize readnone willreturn "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { nofree nosync nounwind readnone speculatable willreturn } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4} +!llvm.ident = !{!5} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 14.0.0 (git@...)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "dwarf-basics-v5.c", directory: "/tmp", checksumkind: CSK_MD5, checksum: "ead340d457001e2ce340630cfa3a9cb8") +!2 = !{i32 7, !"Dwarf Version", i32 5} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 2} +!5 = !{!"clang version 14.0.0 (git@...)"} +!6 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 5, type: !7, scopeLine: 6, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !16) +!7 = !DISubroutineType(types: !8) +!8 = !{!9, !10, !11} +!9 = !DIBasicType(name: "int", size: 16, encoding: DW_ATE_signed) +!10 = !DIBasicType(name: "long", size: 32, encoding: DW_ATE_signed) +!11 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !12, size: 16) +!12 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "X", file: !1, line: 1, size: 16, elements: !13) +!13 = !{!14} +!14 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !12, file: !1, line: 2, baseType: !15, size: 16) +!15 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 16) +!16 = !{!17, !18} +!17 = !DILocalVariable(name: "y", arg: 1, scope: !6, file: !1, line: 5, type: !10) +!18 = !DILocalVariable(name: "p", arg: 2, scope: !6, file: !1, line: 5, type: !11) +!19 = !DILocation(line: 0, scope: !6) +!20 = !DILocation(line: 7, column: 3, scope: !6) diff --git a/llvm/test/DebugInfo/MSP430/ranges_always.ll b/llvm/test/DebugInfo/MSP430/ranges_always.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/MSP430/ranges_always.ll @@ -0,0 +1,241 @@ +; RUN: llc -O0 %s -mtriple=msp430 -filetype=obj -o - -minimize-addr-in-v5=Ranges \ +; RUN: | llvm-dwarfdump -debug-info -debug-addr -debug-rnglists -v - \ +; RUN: | FileCheck --check-prefix=CHECK --check-prefix=RNG \ +; RUN: --implicit-check-not=DW_TAG --implicit-check-not=NULL --implicit-check-not=_pc %s + +; RUN: llc -O0 %s -mtriple=msp430 -filetype=obj -o - -minimize-addr-in-v5=Expressions \ +; RUN: | llvm-dwarfdump -debug-info -debug-addr -debug-rnglists -v - \ +; RUN: | FileCheck --check-prefix=CHECK --check-prefix=EXPRORFORM --check-prefix=EXPR\ +; RUN: --implicit-check-not=DW_TAG --implicit-check-not=NULL --implicit-check-not=_pc %s + +; RUN: llc -O0 %s -mtriple=msp430 -filetype=obj -o - -minimize-addr-in-v5=Form \ +; RUN: | llvm-dwarfdump -debug-info -debug-addr -debug-rnglists -v - \ +; RUN: | FileCheck --check-prefix=CHECK --check-prefix=EXPRORFORM --check-prefix=FORM \ +; RUN: --implicit-check-not=DW_TAG --implicit-check-not=NULL --implicit-check-not=_pc %s + +; Ported from X86 test to cover 2-byte address size case + +; Generated from the following source. f4 is used to put a hole in the CU +; ranges while keeping f2 and f4 in the same section (as opposed to +; -ffunction-sections, which would produce CU ranges, but each function would +; be in a different section, so unable to share addresses). The call to f1 at +; the start of f3 ensures the range for the inlined subroutine doesn't share +; the starting address with f3 (so it can be improved by using a rnglist to +; allow it to share an address it wouldn't already be sharing). + +; Without f6 being in another section, technically we could use a non-zero CU +; low_pc that could act as a base address for all the addresses in the CU & avoid +; the need for these forced rnglists - we don't do that currently, but f6 ensures +; that this test will remain meaningful even if that improvement is made in the +; future. (implementing that would require detecting that all the addresses in +; the CU ranges are in the same section, then picking the lowest such address as +; the base address to make all other addresses relative to) + +; IR from the following, compiled with: +; $ clang -g -c -gdwarf-5 -O1 +; __attribute__((optnone)) void f1() { } +; __attribute__((always_inline)) inline void f2() { +; f1(); +; } +; void f3() { +; f1(); +; f2(); +; } +; __attribute__((nodebug)) void f4() { +; } +; void f5() { +; } +; __attribute__((section(".other"))) void f6() { +; } + +; CHECK-LABEL: .debug_info contents: +; CHECK: DW_TAG_compile_unit +; CHECK: DW_AT_low_pc +; CHECK-SAME: (0x0000) +; RNG: DW_AT_ranges +; RNG-SAME: (indexed (0x3) rangelist = [[CU_RANGE:.*]] +; EXPRORFORM: DW_AT_ranges +; EXPRORFORM-SAME: (indexed (0x0) rangelist = [[CU_RANGE:.*]] +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_low_pc +; CHECK-SAME: (indexed (00000000) address = 0x0000 ".text") +; CHECK: DW_AT_high_pc +; CHECK-SAME: (0x00000002) +; CHECK: DW_AT_name +; CHECK-SAME: "f1" +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_name +; CHECK-SAME: "f2" +; CHECK: DW_TAG_subprogram +; EXPR: DW_AT_low_pc +; EXPR-SAME: (DW_OP_addrx 0x0, DW_OP_const4u 0x2, DW_OP_plus) +; FORM: DW_AT_low_pc +; FORM-SAME: [DW_FORM_LLVM_addrx_offset] (indexed (00000000) + 0x2 address = 0x0002 ".text") +; EXPRORFORM: DW_AT_high_pc +; EXPRORFORM-SAME: (0x0000000a) +; RNG: DW_AT_ranges +; RNG-SAME: (indexed (0x0) rangelist = [[F3_RANGE:.*]] +; CHECK: DW_AT_name +; CHECK-SAME: "f3" +; CHECK: DW_TAG_inlined_subroutine +; EXPR: DW_AT_low_pc +; EXPR-SAME: [DW_FORM_exprloc] (DW_OP_addrx 0x0, DW_OP_const4u 0x6, DW_OP_plus) +; FORM: DW_AT_low_pc +; FORM-SAME: [DW_FORM_LLVM_addrx_offset] (indexed (00000000) + 0x6 address = 0x0006 ".text") +; EXPRORFORM: DW_AT_high_pc +; EXPRORFORM-SAME: (0x00000004) +; RNG: DW_AT_ranges +; RNG-SAME: (indexed (0x1) rangelist = [[INL_RANGE:.*]] +; CHECK: DW_TAG_call_site +; RNG: DW_AT_call_return_pc +; RNG-SAME: (indexed (00000001) address = 0x0006 ".text") +; EXPR: DW_AT_call_return_pc +; EXPR-SAME: [DW_FORM_exprloc] (DW_OP_addrx 0x0, DW_OP_const4u 0x6, DW_OP_plus) +; FORM: DW_AT_call_return_pc +; FORM-SAME: [DW_FORM_LLVM_addrx_offset] (indexed (00000000) + 0x6 address = 0x0006 ".text") +; CHECK: DW_TAG_call_site +; RNG: DW_AT_call_return_pc +; RNG-SAME: (indexed (00000002) address = 0x000a ".text") +; EXPR: DW_AT_call_return_pc +; EXPR-SAME: [DW_FORM_exprloc] (DW_OP_addrx 0x0, DW_OP_const4u 0xa, DW_OP_plus) +; FORM: DW_AT_call_return_pc +; FORM-SAME: [DW_FORM_LLVM_addrx_offset] (indexed (00000000) + 0xa address = 0x000a ".text") +; CHECK: NULL +; CHECK: DW_TAG_subprogram +; EXPR: DW_AT_low_pc +; EXPR-SAME: [DW_FORM_exprloc] (DW_OP_addrx 0x0, DW_OP_const4u 0xe, DW_OP_plus) +; FORM: DW_AT_low_pc +; FORM-SAME: [DW_FORM_LLVM_addrx_offset] (indexed (00000000) + 0xe address = 0x000e ".text") +; EXPRORFORM: DW_AT_high_pc +; EXPRORFORM-SAME: (0x00000002) +; RNG: DW_AT_ranges +; RNG-SAME: (indexed (0x2) rangelist = [[F5_RANGE:.*]] +; CHECK: DW_AT_name +; CHECK-SAME: "f5" +; CHECK: DW_TAG_subprogram +; CHECK: DW_AT_low_pc [DW_FORM_addrx] (indexed ( +; RNG-SAME: 00000003 +; EXPRORFORM-SAME: 00000001 +; CHECK: ) address = 0x0000 ".other") +; CHECK: DW_AT_high_pc +; CHECK-SAME: (0x00000006) +; CHECK: DW_AT_name +; CHECK-SAME: "f6" +; CHECK: DW_TAG_inlined_subroutine +; RNG: DW_AT_low_pc +; RNG-SAME: (indexed (00000003) address = 0x0000 ".other") +; EXPRORFORM: DW_AT_low_pc +; EXPRORFORM-SAME: (indexed (00000001) address = 0x0000 ".other") +; CHECK: DW_AT_high_pc +; CHECK-SAME: (0x00000004) +; CHECK: DW_TAG_call_site +; CHECK: DW_AT_call_return_pc +; CHECK: NULL +; CHECK: NULL + +; CHECK-LABEL: .debug_addr contents: +; CHECK: 0x00000000: Address table +; CHECK-NEXT: Addrs: [ +; CHECK-NEXT: 0x0000 +; RNG-NEXT: 0x0006 +; RNG-NEXT: 0x000a +; CHECK-NEXT: 0x0000 +; RNG-NEXT: 0x0004 +; CHECK-NEXT: ] + +; CHECK-LABEL: .debug_rnglists contents: +; RNG: 0x00000000: range list header: {{.*}}, offset_entry_count = 0x00000004 +; EXPRORFORM: 0x00000000: range list header: {{.*}}, offset_entry_count = 0x00000001 +; CHECK: ranges: +; RNG-NEXT: [[F3_RANGE]]: [DW_RLE_base_addressx]: +; RNG-SAME: 0x0000 +; RNG-NEXT: [DW_RLE_offset_pair ] +; RNG-NEXT: [DW_RLE_end_of_list ] + +; RNG-NEXT: [[INL_RANGE]]: [DW_RLE_base_addressx]: +; RNG-SAME: 0x0000 +; RNG-NEXT: [DW_RLE_offset_pair ] +; RNG-NEXT: [DW_RLE_end_of_list ] + +; RNG-NEXT: [[F5_RANGE]]: [DW_RLE_base_addressx]: +; RNG-SAME: 0x0000 +; RNG-NEXT: [DW_RLE_offset_pair ] +; RNG-NEXT: [DW_RLE_end_of_list ] + +; CHECK-NEXT: [[CU_RANGE]]: [DW_RLE_base_addressx]: +; CHECK-SAME: 0x0000 +; CHECK-NEXT: [DW_RLE_offset_pair ] +; CHECK-NEXT: [DW_RLE_offset_pair ] +; RNG-NEXT: [DW_RLE_startx_length]: +; RNG-SAME: 0x0003 +; EXPRORFORM-NEXT: [DW_RLE_startx_length]: +; EXPRORFORM-SAME: 0x0001 +; CHECK-NEXT: [DW_RLE_end_of_list ] + +; Function Attrs: mustprogress noinline nounwind optnone uwtable +define dso_local void @_Z2f1v() local_unnamed_addr #0 !dbg !7 { +entry: + ret void, !dbg !12 +} + +; Function Attrs: mustprogress nounwind uwtable +define dso_local void @_Z2f3v() local_unnamed_addr #1 !dbg !13 { +entry: + call void @_Z2f1v(), !dbg !14 + call void @_Z2f1v() #3, !dbg !15 + ret void, !dbg !18 +} + +; Function Attrs: mustprogress nofree norecurse nosync nounwind readnone uwtable willreturn +define dso_local void @_Z2f4v() local_unnamed_addr #2 { +entry: + ret void +} + +; Function Attrs: mustprogress nofree norecurse nosync nounwind readnone uwtable willreturn +define dso_local void @_Z2f5v() local_unnamed_addr #2 !dbg !19 { +entry: + ret void, !dbg !20 +} + +; Function Attrs: mustprogress nounwind uwtable +define dso_local void @_Z2f6v() local_unnamed_addr #1 section ".other" !dbg !21 { +entry: + call void @_Z2f1v() #3, !dbg !22 + ret void, !dbg !24 +} + +attributes #0 = { mustprogress noinline nounwind optnone uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #1 = { mustprogress nounwind uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #2 = { mustprogress nofree norecurse nosync nounwind readnone uwtable willreturn "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #3 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!2, !3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 14.0.0 (git@github.com:llvm/llvm-project.git e2c3dc6fc76e767f08249f6d2c36e41660a4e331)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "/usr/local/google/home/blaikie/dev/scratch/test.cpp", directory: "/usr/local/google/home/blaikie/dev/llvm/src", checksumkind: CSK_MD5, checksum: "e70db21a276125757057e729999c09c7") +!2 = !{i32 7, !"Dwarf Version", i32 5} +!3 = !{i32 2, !"Debug Info Version", i32 3} +!4 = !{i32 1, !"wchar_size", i32 4} +!5 = !{i32 7, !"uwtable", i32 1} +!6 = !{!"clang version 14.0.0 (git@github.com:llvm/llvm-project.git e2c3dc6fc76e767f08249f6d2c36e41660a4e331)"} +!7 = distinct !DISubprogram(name: "f1", linkageName: "_Z2f1v", scope: !8, file: !8, line: 1, type: !9, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11) +!8 = !DIFile(filename: "scratch/test.cpp", directory: "/usr/local/google/home/blaikie/dev", checksumkind: CSK_MD5, checksum: "e70db21a276125757057e729999c09c7") +!9 = !DISubroutineType(types: !10) +!10 = !{null} +!11 = !{} +!12 = !DILocation(line: 1, column: 38, scope: !7) +!13 = distinct !DISubprogram(name: "f3", linkageName: "_Z2f3v", scope: !8, file: !8, line: 5, type: !9, scopeLine: 5, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11) +!14 = !DILocation(line: 6, column: 3, scope: !13) +!15 = !DILocation(line: 3, column: 3, scope: !16, inlinedAt: !17) +!16 = distinct !DISubprogram(name: "f2", linkageName: "_Z2f2v", scope: !8, file: !8, line: 2, type: !9, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11) +!17 = distinct !DILocation(line: 7, column: 3, scope: !13) +!18 = !DILocation(line: 8, column: 1, scope: !13) +!19 = distinct !DISubprogram(name: "f5", linkageName: "_Z2f5v", scope: !8, file: !8, line: 11, type: !9, scopeLine: 11, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11) +!20 = !DILocation(line: 12, column: 1, scope: !19) +!21 = distinct !DISubprogram(name: "f6", linkageName: "_Z2f6v", scope: !8, file: !8, line: 13, type: !9, scopeLine: 13, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11) +!22 = !DILocation(line: 3, column: 3, scope: !16, inlinedAt: !23) +!23 = distinct !DILocation(line: 14, column: 3, scope: !21) +!24 = !DILocation(line: 15, column: 1, scope: !21) diff --git a/llvm/test/tools/llvm-dwarfdump/X86/debug_addr_invalid_addr_size.s b/llvm/test/tools/llvm-dwarfdump/X86/debug_addr_invalid_addr_size.s --- a/llvm/test/tools/llvm-dwarfdump/X86/debug_addr_invalid_addr_size.s +++ b/llvm/test/tools/llvm-dwarfdump/X86/debug_addr_invalid_addr_size.s @@ -4,7 +4,7 @@ # CHECK: .debug_addr contents: # CHECK-NOT: {{.}} -# ERR: unsupported address size 3 (4 and 8 are supported) +# ERR: unsupported address size: 3 (supported are 2, 4, 8) # ERR-NOT: {{.}} # invalid addr size diff --git a/llvm/test/tools/llvm-dwarfdump/X86/debug_rnglists_invalid.s b/llvm/test/tools/llvm-dwarfdump/X86/debug_rnglists_invalid.s --- a/llvm/test/tools/llvm-dwarfdump/X86/debug_rnglists_invalid.s +++ b/llvm/test/tools/llvm-dwarfdump/X86/debug_rnglists_invalid.s @@ -27,7 +27,7 @@ # CHECK-NOT: error: # CHECK: error: .debug_rnglists table at offset 0x22 has too small length (0xb) to contain a complete header # CHECK-NEXT: error: unrecognised .debug_rnglists table version 4 in table at offset 0x2d -# CHECK-NEXT: error: .debug_rnglists table at offset 0x39 has unsupported address size 2 +# CHECK-NEXT: error: .debug_rnglists table at offset 0x39 has unsupported address size: 3 # CHECK-NEXT: error: .debug_rnglists table at offset 0x45 has unsupported segment selector size 4 # CHECK-NEXT: error: .debug_rnglists table at offset 0x51 has more offset entries (12345678) than there is space for # CHECK-NEXT: error: read past end of table when reading DW_RLE_start_end encoding at offset 0x69 @@ -71,7 +71,7 @@ # Table 4 (unsupported address size) .long 8 # Table length .short 5 # Version -.byte 2 # Address size +.byte 3 # Address size .byte 0 # Segment selector size .long 0 # Offset entry count diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFDebugArangeSetTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDebugArangeSetTest.cpp --- a/llvm/unittests/DebugInfo/DWARF/DWARFDebugArangeSetTest.cpp +++ b/llvm/unittests/DebugInfo/DWARF/DWARFDebugArangeSetTest.cpp @@ -75,14 +75,14 @@ "\x0c\x00\x00\x00" // Length "\x02\x00" // Version "\x00\x00\x00\x00" // Debug Info Offset - "\x02" // Address Size (not supported) + "\x03" // Address Size (not supported) "\x00" // Segment Selector Size // No padding "\x00\x00\x00\x00"; // Termination tuple ExpectExtractError( DebugArangesSecRaw, - "address range table at offset 0x0 has unsupported address size: 2 " - "(4 and 8 supported)"); + "address range table at offset 0x0 has unsupported address size: 3 " + "(supported are 2, 4, 8)"); } TEST(DWARFDebugArangeSet, UnsupportedSegmentSelectorSize) {