[DebugInfo] Expand ability to load 2-byte addresses in dwarf sections

Some dwarf loaders in LLVM are hard-coded to only accept 4-byte and 8-byte address sizes. This patch generalizes acceptance into `DWARFContext::isAddressSizeSupported` and provides a common way to generate rejection errors.

The MSP430 target has been given new tests to cover dwarf loading cases that previously failed due to 2-byte addresses.

Reviewed By: dblaikie

Differential Revision: https://reviews.llvm.org/D111953
This commit is contained in:
Jack Anderson 2021-10-21 17:29:34 -07:00 committed by David Blaikie
parent 09b95b9dc9
commit d7733f8422
13 changed files with 549 additions and 49 deletions

View File

@ -375,6 +375,23 @@ public:
static bool isAddressSizeSupported(unsigned AddressSize) {
return llvm::is_contained(getSupportedAddressSizes(), AddressSize);
}
template <typename... Ts>
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<StringError>(Stream.str(), EC);
}
std::shared_ptr<DWARFContext> getDWOContext(StringRef AbsolutePath);

View File

@ -49,12 +49,7 @@ public:
/// 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:

View File

@ -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 @@ Error DWARFDebugAddrTable::extractAddresses(const DWARFDataExtractor &Data,
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 @@ void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
}
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);

View File

@ -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 @@ Error DWARFDebugArangeSet::extract(DWARFDataExtractor data,
"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 "

View File

@ -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 @@ Error DWARFDebugRangeList::extract(const DWARFDataExtractor &data,
"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 @@ Error DWARFDebugRangeList::extract(const DWARFDataExtractor &data,
}
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 " <End of list>\n", Offset);
}

View File

@ -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 @@ Error DWARFListTableHeader::extract(DWARFDataExtractor Data,
"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

View File

@ -315,15 +315,10 @@ bool DWARFUnitHeader::extract(DWARFContext &Context,
return false;
}
if (!DWARFContext::isAddressSizeSupported(getAddressByteSize())) {
SmallVector<std::string, 3> 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;
}

View File

@ -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 <End of list>
; 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)

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -75,14 +75,14 @@ TEST(DWARFDebugArangeSet, UnsupportedAddressSize) {
"\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) {