Skip to content

Commit d7733f8

Browse files
jackoalandwblaikie
authored andcommitted
[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
1 parent 09b95b9 commit d7733f8

File tree

13 files changed

+549
-49
lines changed

13 files changed

+549
-49
lines changed

llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,23 @@ class DWARFContext : public DIContext {
375375
static bool isAddressSizeSupported(unsigned AddressSize) {
376376
return llvm::is_contained(getSupportedAddressSizes(), AddressSize);
377377
}
378+
template <typename... Ts>
379+
static Error checkAddressSizeSupported(unsigned AddressSize,
380+
std::error_code EC, char const *Fmt,
381+
const Ts &...Vals) {
382+
if (isAddressSizeSupported(AddressSize))
383+
return Error::success();
384+
std::string Buffer;
385+
raw_string_ostream Stream(Buffer);
386+
Stream << format(Fmt, Vals...)
387+
<< " has unsupported address size: " << AddressSize
388+
<< " (supported are ";
389+
ListSeparator LS;
390+
for (unsigned Size : DWARFContext::getSupportedAddressSizes())
391+
Stream << LS << Size;
392+
Stream << ')';
393+
return make_error<StringError>(Stream.str(), EC);
394+
}
378395

379396
std::shared_ptr<DWARFContext> getDWOContext(StringRef AbsolutePath);
380397

llvm/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,7 @@ class DWARFDebugRangeList {
4949
/// 2. An address, which defines the appropriate base address for
5050
/// use in interpreting the beginning and ending address offsets of
5151
/// subsequent entries of the location list.
52-
bool isBaseAddressSelectionEntry(uint8_t AddressSize) const {
53-
assert(AddressSize == 4 || AddressSize == 8);
54-
if (AddressSize == 4)
55-
return StartAddress == -1U;
56-
return StartAddress == -1ULL;
57-
}
52+
bool isBaseAddressSelectionEntry(uint8_t AddressSize) const;
5853
};
5954

6055
private:

llvm/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
#include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h"
1010
#include "llvm/BinaryFormat/Dwarf.h"
11-
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
11+
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
1212

1313
using namespace llvm;
1414

@@ -18,12 +18,10 @@ Error DWARFDebugAddrTable::extractAddresses(const DWARFDataExtractor &Data,
1818
assert(EndOffset >= *OffsetPtr);
1919
uint64_t DataSize = EndOffset - *OffsetPtr;
2020
assert(Data.isValidOffsetForDataOfSize(*OffsetPtr, DataSize));
21-
if (AddrSize != 4 && AddrSize != 8)
22-
return createStringError(errc::not_supported,
23-
"address table at offset 0x%" PRIx64
24-
" has unsupported address size %" PRIu8
25-
" (4 and 8 are supported)",
26-
Offset, AddrSize);
21+
if (Error SizeErr = DWARFContext::checkAddressSizeSupported(
22+
AddrSize, errc::not_supported, "address table at offset 0x%" PRIx64,
23+
Offset))
24+
return SizeErr;
2725
if (DataSize % AddrSize != 0) {
2826
invalidateLength();
2927
return createStringError(errc::invalid_argument,
@@ -148,8 +146,20 @@ void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
148146
}
149147

150148
if (Addrs.size() > 0) {
151-
const char *AddrFmt =
152-
(AddrSize == 4) ? "0x%8.8" PRIx64 "\n" : "0x%16.16" PRIx64 "\n";
149+
const char *AddrFmt;
150+
switch (AddrSize) {
151+
case 2:
152+
AddrFmt = "0x%4.4" PRIx64 "\n";
153+
break;
154+
case 4:
155+
AddrFmt = "0x%8.8" PRIx64 "\n";
156+
break;
157+
case 8:
158+
AddrFmt = "0x%16.16" PRIx64 "\n";
159+
break;
160+
default:
161+
llvm_unreachable("unsupported address size");
162+
}
153163
OS << "Addrs: [\n";
154164
for (uint64_t Addr : Addrs)
155165
OS << format(AddrFmt, Addr);

llvm/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"
1010
#include "llvm/BinaryFormat/Dwarf.h"
11+
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
1112
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
1213
#include "llvm/Support/Errc.h"
1314
#include "llvm/Support/Format.h"
@@ -87,12 +88,10 @@ Error DWARFDebugArangeSet::extract(DWARFDataExtractor data,
8788
"the length of address range table at offset "
8889
"0x%" PRIx64 " exceeds section size",
8990
Offset);
90-
if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8)
91-
return createStringError(errc::invalid_argument,
92-
"address range table at offset 0x%" PRIx64
93-
" has unsupported address size: %d "
94-
"(4 and 8 supported)",
95-
Offset, HeaderData.AddrSize);
91+
if (Error SizeErr = DWARFContext::checkAddressSizeSupported(
92+
HeaderData.AddrSize, errc::invalid_argument,
93+
"address range table at offset 0x%" PRIx64, Offset))
94+
return SizeErr;
9695
if (HeaderData.SegSize != 0)
9796
return createStringError(errc::not_supported,
9897
"non-zero segment selector size in address range "

llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@
1616

1717
using namespace llvm;
1818

19+
bool DWARFDebugRangeList::RangeListEntry::isBaseAddressSelectionEntry(
20+
uint8_t AddressSize) const {
21+
assert(DWARFContext::isAddressSizeSupported(AddressSize));
22+
return StartAddress == dwarf::computeTombstoneAddress(AddressSize);
23+
}
24+
1925
void DWARFDebugRangeList::clear() {
2026
Offset = -1ULL;
2127
AddressSize = 0;
@@ -30,9 +36,10 @@ Error DWARFDebugRangeList::extract(const DWARFDataExtractor &data,
3036
"invalid range list offset 0x%" PRIx64, *offset_ptr);
3137

3238
AddressSize = data.getAddressSize();
33-
if (AddressSize != 4 && AddressSize != 8)
34-
return createStringError(errc::invalid_argument,
35-
"invalid address size: %" PRIu8, AddressSize);
39+
if (Error SizeErr = DWARFContext::checkAddressSizeSupported(
40+
AddressSize, errc::invalid_argument,
41+
"range list at offset 0x%" PRIx64, *offset_ptr))
42+
return SizeErr;
3643
Offset = *offset_ptr;
3744
while (true) {
3845
RangeListEntry Entry;
@@ -58,12 +65,22 @@ Error DWARFDebugRangeList::extract(const DWARFDataExtractor &data,
5865
}
5966

6067
void DWARFDebugRangeList::dump(raw_ostream &OS) const {
61-
for (const RangeListEntry &RLE : Entries) {
62-
const char *format_str =
63-
(AddressSize == 4 ? "%08" PRIx64 " %08" PRIx64 " %08" PRIx64 "\n"
64-
: "%08" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n");
65-
OS << format(format_str, Offset, RLE.StartAddress, RLE.EndAddress);
68+
const char *AddrFmt;
69+
switch (AddressSize) {
70+
case 2:
71+
AddrFmt = "%08" PRIx64 " %04" PRIx64 " %04" PRIx64 "\n";
72+
break;
73+
case 4:
74+
AddrFmt = "%08" PRIx64 " %08" PRIx64 " %08" PRIx64 "\n";
75+
break;
76+
case 8:
77+
AddrFmt = "%08" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n";
78+
break;
79+
default:
80+
llvm_unreachable("unsupported address size");
6681
}
82+
for (const RangeListEntry &RLE : Entries)
83+
OS << format(AddrFmt, Offset, RLE.StartAddress, RLE.EndAddress);
6784
OS << format("%08" PRIx64 " <End of list>\n", Offset);
6885
}
6986

llvm/lib/DebugInfo/DWARF/DWARFListTable.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "llvm/DebugInfo/DWARF/DWARFListTable.h"
1010
#include "llvm/BinaryFormat/Dwarf.h"
11+
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
1112
#include "llvm/Support/Errc.h"
1213
#include "llvm/Support/Error.h"
1314
#include "llvm/Support/Format.h"
@@ -54,11 +55,10 @@ Error DWARFListTableHeader::extract(DWARFDataExtractor Data,
5455
"unrecognised %s table version %" PRIu16
5556
" in table at offset 0x%" PRIx64,
5657
SectionName.data(), HeaderData.Version, HeaderOffset);
57-
if (HeaderData.AddrSize != 4 && HeaderData.AddrSize != 8)
58-
return createStringError(errc::not_supported,
59-
"%s table at offset 0x%" PRIx64
60-
" has unsupported address size %" PRIu8,
61-
SectionName.data(), HeaderOffset, HeaderData.AddrSize);
58+
if (Error SizeErr = DWARFContext::checkAddressSizeSupported(
59+
HeaderData.AddrSize, errc::not_supported,
60+
"%s table at offset 0x%" PRIx64, SectionName.data(), HeaderOffset))
61+
return SizeErr;
6262
if (HeaderData.SegSize != 0)
6363
return createStringError(errc::not_supported,
6464
"%s table at offset 0x%" PRIx64

llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -315,15 +315,10 @@ bool DWARFUnitHeader::extract(DWARFContext &Context,
315315
return false;
316316
}
317317

318-
if (!DWARFContext::isAddressSizeSupported(getAddressByteSize())) {
319-
SmallVector<std::string, 3> Sizes;
320-
for (auto Size : DWARFContext::getSupportedAddressSizes())
321-
Sizes.push_back(std::to_string(Size));
322-
Context.getWarningHandler()(createStringError(
323-
errc::invalid_argument,
324-
"DWARF unit at offset 0x%8.8" PRIx64 " "
325-
"has unsupported address size %" PRIu8 ", supported are %s",
326-
Offset, getAddressByteSize(), llvm::join(Sizes, ", ").c_str()));
318+
if (Error SizeErr = DWARFContext::checkAddressSizeSupported(
319+
getAddressByteSize(), errc::invalid_argument,
320+
"DWARF unit at offset 0x%8.8" PRIx64, Offset)) {
321+
Context.getWarningHandler()(std::move(SizeErr));
327322
return false;
328323
}
329324

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
; RUN: llc -O0 -mtriple=msp430 -filetype=obj %s -o %t
2+
; RUN: llvm-dwarfdump -v %t | FileCheck %s
3+
4+
; Ported from generic test to cover 2-byte address size case
5+
6+
; Check that we emit ranges for this which has a non-traditional section and a normal section.
7+
8+
; CHECK: DW_TAG_compile_unit
9+
; CHECK: DW_AT_ranges
10+
; CHECK: DW_TAG_subprogram
11+
; CHECK: DW_AT_low_pc
12+
; CHECK: DW_AT_high_pc
13+
; CHECK: DW_TAG_subprogram
14+
; CHECK: DW_AT_low_pc
15+
; CHECK: DW_AT_high_pc
16+
17+
; CHECK: .debug_ranges contents:
18+
; CHECK-NEXT: 00000000 0000 0030
19+
; CHECK-NEXT: 00000000 0000 0030
20+
; CHECK-NEXT: 00000000 <End of list>
21+
22+
; Function Attrs: nounwind uwtable
23+
define i32 @foo(i32 %a) #0 section "__TEXT,__foo" !dbg !4 {
24+
entry:
25+
%a.addr = alloca i32, align 4
26+
store i32 %a, i32* %a.addr, align 4
27+
call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !13, metadata !DIExpression()), !dbg !14
28+
%0 = load i32, i32* %a.addr, align 4, !dbg !15
29+
%add = add nsw i32 %0, 5, !dbg !15
30+
ret i32 %add, !dbg !15
31+
}
32+
33+
; Function Attrs: nounwind readnone
34+
declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
35+
36+
; Function Attrs: nounwind uwtable
37+
define i32 @bar(i32 %a) #0 !dbg !9 {
38+
entry:
39+
%a.addr = alloca i32, align 4
40+
store i32 %a, i32* %a.addr, align 4
41+
call void @llvm.dbg.declare(metadata i32* %a.addr, metadata !16, metadata !DIExpression()), !dbg !17
42+
%0 = load i32, i32* %a.addr, align 4, !dbg !18
43+
%add = add nsw i32 %0, 5, !dbg !18
44+
ret i32 %add, !dbg !18
45+
}
46+
47+
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" }
48+
attributes #1 = { nounwind readnone }
49+
50+
!llvm.dbg.cu = !{!0}
51+
!llvm.module.flags = !{!10, !11}
52+
!llvm.ident = !{!12}
53+
54+
!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)
55+
!1 = !DIFile(filename: "foo.c", directory: "/usr/local/google/home/echristo")
56+
!2 = !{}
57+
!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)
58+
!5 = !DIFile(filename: "foo.c", directory: "/usr/local/google/home/echristo")
59+
!6 = !DISubroutineType(types: !7)
60+
!7 = !{!8, !8}
61+
!8 = !DIBasicType(tag: DW_TAG_base_type, name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
62+
!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)
63+
!10 = !{i32 2, !"Dwarf Version", i32 4}
64+
!11 = !{i32 1, !"Debug Info Version", i32 3}
65+
!12 = !{!"clang version 3.5.0 (trunk 204164) (llvm/trunk 204183)"}
66+
!13 = !DILocalVariable(name: "a", line: 1, arg: 1, scope: !4, file: !5, type: !8)
67+
!14 = !DILocation(line: 1, scope: !4)
68+
!15 = !DILocation(line: 2, scope: !4)
69+
!16 = !DILocalVariable(name: "a", line: 5, arg: 1, scope: !9, file: !5, type: !8)
70+
!17 = !DILocation(line: 5, scope: !9)
71+
!18 = !DILocation(line: 6, scope: !9)
72+

0 commit comments

Comments
 (0)