Skip to content

Commit 4f60a42

Browse files
committed
DWARFVerifier: Skip resolution failures for locations in dwo files
When reading location lists in dwo files the addresses cannot be resolved, but that's not a problem. Long term this probably should be fixed with a different API that exposes location expressions without the need to resolve the address ranges, since that's all the verifier (in its current state) requires. (though the verifier should probably also eventually verify the address ranges in location lists are a subset of the enclosing scope's address range)
1 parent e5c3b97 commit 4f60a42

File tree

5 files changed

+81
-7
lines changed

5 files changed

+81
-7
lines changed

llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
1616
#include "llvm/DebugInfo/DWARF/DWARFLocationExpression.h"
1717
#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
18+
#include "llvm/Support/Errc.h"
1819
#include <cstdint>
1920

2021
namespace llvm {
@@ -142,6 +143,22 @@ class DWARFDebugLoclists final : public DWARFLocationTable {
142143
uint16_t Version;
143144
};
144145

146+
class ResolverError : public ErrorInfo<ResolverError> {
147+
public:
148+
static char ID;
149+
150+
ResolverError(uint32_t Index, dwarf::LoclistEntries Kind) : Index(Index), Kind(Kind) {}
151+
152+
void log(raw_ostream &OS) const override;
153+
std::error_code convertToErrorCode() const override {
154+
return llvm::errc::invalid_argument;
155+
}
156+
157+
private:
158+
uint32_t Index;
159+
dwarf::LoclistEntries Kind;
160+
};
161+
145162
} // end namespace llvm
146163

147164
#endif // LLVM_DEBUGINFO_DWARF_DWARFDEBUGLOC_H

llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,7 @@ class DWARFLocationInterpreter {
4141
} // namespace
4242

4343
static Error createResolverError(uint32_t Index, unsigned Kind) {
44-
return createStringError(errc::invalid_argument,
45-
"Unable to resolve indirect address %u for: %s",
46-
Index, dwarf::LocListEncodingString(Kind).data());
44+
return make_error<ResolverError>(Index, (dwarf::LoclistEntries)Kind);
4745
}
4846

4947
Expected<Optional<DWARFLocationExpression>>
@@ -404,3 +402,10 @@ void DWARFDebugLoclists::dumpRange(uint64_t StartOffset, uint64_t Size,
404402
OS << '\n';
405403
}
406404
}
405+
406+
void llvm::ResolverError::log(raw_ostream &OS) const {
407+
OS << format("unable to resolve indirect address %u for: %s", Index,
408+
dwarf::LocListEncodingString(Kind).data());
409+
}
410+
411+
char llvm::ResolverError::ID;

llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,16 @@ unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die,
534534
ReportError("DIE has invalid DW_AT_stmt_list encoding:");
535535
break;
536536
case DW_AT_location: {
537+
// FIXME: It might be nice if there's a way to walk location expressions
538+
// without trying to resolve the address ranges - it'd be a more efficient
539+
// API (since the API is currently unnecessarily resolving addresses for
540+
// this use case which only wants to validate the expressions themselves) &
541+
// then the expressions could be validated even if the addresses can't be
542+
// resolved.
543+
// That sort of API would probably look like a callback "for each
544+
// expression" with some way to lazily resolve the address ranges when
545+
// needed (& then the existing API used here could be built on top of that -
546+
// using the callback API to build the data structure and return it).
537547
if (Expected<std::vector<DWARFLocationExpression>> Loc =
538548
Die.getLocations(DW_AT_location)) {
539549
for (const auto &Entry : *Loc) {
@@ -547,8 +557,12 @@ unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die,
547557
if (Error || !Expression.verify(U))
548558
ReportError("DIE contains invalid DWARF expression:");
549559
}
550-
} else
551-
ReportError(toString(Loc.takeError()));
560+
} else if (Error E = handleErrors(
561+
Loc.takeError(), [&](std::unique_ptr<ResolverError> E) {
562+
return U->isDWOUnit() ? Error::success()
563+
: Error(std::move(E));
564+
}))
565+
ReportError(toString(std::move(E)));
552566
break;
553567
}
554568
case DW_AT_specification:

llvm/test/tools/llvm-dwarfdump/X86/verify_split_cu.s

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
.quad 2 # DWO ID
2929
.byte 1 # Abbrev [1] DW_TAG_compile_unit
3030
.byte 0 # DW_AT_decl_file
31-
.byte 0 # DW_AT_location
31+
.byte 0 # DW_AT_location
3232
.Ldebug_info_dwo_end2:
3333
.Ldebug_info_dwo_prestart3:
3434
.long .Ldebug_info_dwo_end3-.Ldebug_info_dwo_start3 # Length of Unit
@@ -57,6 +57,16 @@
5757
.long 0 # DW_AT_stmt_list
5858
.byte 0 # DW_AT_decl_file
5959
.Ldebug_info_dwo_end4:
60+
.long .Ldebug_info_dwo_end5-.Ldebug_info_dwo_start5 # Length of Unit
61+
.Ldebug_info_dwo_start5:
62+
.short 5 # DWARF version number
63+
.byte 5 # DWARF Unit Type
64+
.byte 8 # Address Size (in bytes)
65+
.long 0 # Offset Into Abbrev. Section
66+
.quad 2 # DWO ID
67+
.byte 4 # Abbrev [1] DW_TAG_compile_unit
68+
.uleb128 0 # DW_AT_location
69+
.Ldebug_info_dwo_end5:
6070
.section .debug_abbrev.dwo,"e",@progbits
6171
.byte 1 # Abbreviation Code
6272
.byte 17 # DW_TAG_compile_unit
@@ -83,6 +93,13 @@
8393
.byte 11 # DW_FORM_data1
8494
.byte 0 # EOM(1)
8595
.byte 0 # EOM(2)
96+
.byte 4 # Abbreviation Code
97+
.byte 17 # DW_TAG_compile_unit
98+
.byte 0 # DW_CHILDREN_no
99+
.byte 2 # DW_AT_location
100+
.byte 34 # DW_FORM_loclistx
101+
.byte 0 # EOM(1)
102+
.byte 0 # EOM(2)
86103
.byte 0 # EOM(3)
87104
.section .debug_line.dwo,"e",@progbits
88105
.Ltmp2:
@@ -122,3 +139,24 @@
122139
.byte 0x36, 0xb7, 0x17, 0xbf
123140
.Lprologue_end0:
124141
.Ldebug_line_end0:
142+
.section .debug_loclists.dwo,"e",@progbits
143+
.long .Ldebug_list_header_end0-.Ldebug_list_header_start0 # Length
144+
.Ldebug_list_header_start0:
145+
.short 5 # Version
146+
.byte 8 # Address size
147+
.byte 0 # Segment selector size
148+
.long 1 # Offset entry count
149+
.Lloclists_table_base0:
150+
.long .Ldebug_loc0-.Lloclists_table_base0
151+
.Ldebug_loc0:
152+
.byte 1 # DW_LLE_base_addressx
153+
.byte 0 # base address index
154+
.byte 4 # DW_LLE_offset_pair
155+
.uleb128 0 # starting offset
156+
.uleb128 1 # ending offset
157+
.byte 3 # Loc expr size
158+
.byte 17 # DW_OP_consts
159+
.byte 3 # 3
160+
.byte 159 # DW_OP_stack_value
161+
.byte 0 # DW_LLE_end_of_list
162+
.Ldebug_list_header_end0:

llvm/unittests/DebugInfo/DWARF/DWARFDieTest.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ TEST(DWARFDie, getLocations) {
8787
Die.getLocations(DW_AT_vtable_elem_location),
8888
Failed<ErrorInfoBase>(testing::Property(
8989
&ErrorInfoBase::message,
90-
"Unable to resolve indirect address 1 for: DW_LLE_startx_length")));
90+
"unable to resolve indirect address 1 for: DW_LLE_startx_length")));
9191

9292
EXPECT_THAT_EXPECTED(
9393
Die.getLocations(DW_AT_call_data_location),

0 commit comments

Comments
 (0)