[llvm] 089c0f5 - [DWARF] Add an api to get "interpreted" location lists
Pavel Labath via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 20 04:27:04 PST 2019
Author: Pavel Labath
Date: 2019-11-20T13:25:18+01:00
New Revision: 089c0f581492cd6e2a3d2927be3fbf60ea2d7e62
URL: https://github.com/llvm/llvm-project/commit/089c0f581492cd6e2a3d2927be3fbf60ea2d7e62
DIFF: https://github.com/llvm/llvm-project/commit/089c0f581492cd6e2a3d2927be3fbf60ea2d7e62.diff
LOG: [DWARF] Add an api to get "interpreted" location lists
Summary:
This patch adds DWARFDie::getLocations, which returns the location
expressions for a given attribute (typically DW_AT_location). It handles
both "inline" locations and references to the external location list
sections (currently only of the DW_FORM_sec_offset type). It is
implemented on top of DWARFUnit::findLoclistFromOffset, which is also
added in this patch. I tried to make their signatures similar to the
equivalent range list functionality.
The actual location list interpretation logic is in
DWARFLocationTable::visitAbsoluteLocationList. This part is not
equivalent to the range list code, but this deviation is motivated by a
desire to reuse the same location list parsing code within lldb.
The functionality is tested via a c++ unit test of the DWARFDie API.
Reviewers: dblaikie, JDevlieghere, SouraVX
Subscribers: mgorny, hiraditya, cmtice, probinson, llvm-commits, aprantl
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D70394
Added:
llvm/unittests/DebugInfo/DWARF/DWARFDieTest.cpp
Modified:
llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h
llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h
llvm/include/llvm/DebugInfo/DWARF/DWARFLocationExpression.h
llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
llvm/lib/ObjectYAML/DWARFEmitter.cpp
llvm/unittests/DebugInfo/DWARF/CMakeLists.txt
Removed:
################################################################################
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h
index 2ca98cfcfff7..8ac3e2add882 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h
@@ -63,6 +63,11 @@ class DWARFLocationTable {
const MCRegisterInfo *MRI, DWARFUnit *U,
DIDumpOptions DumpOpts, unsigned Indent) const;
+ Error visitAbsoluteLocationList(
+ uint64_t Offset, Optional<object::SectionedAddress> BaseAddr,
+ std::function<Optional<object::SectionedAddress>(uint32_t)> LookupAddr,
+ function_ref<bool(Expected<DWARFLocationExpression>)> Callback) const;
+
protected:
DWARFDataExtractor Data;
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h
index 52a0247b3e42..158bd82edee0 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDie.h
@@ -18,6 +18,7 @@
#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"
#include "llvm/DebugInfo/DWARF/DWARFAttribute.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
#include <cassert>
#include <cstdint>
#include <iterator>
@@ -231,6 +232,9 @@ class DWARFDie {
bool addressRangeContainsAddress(const uint64_t Address) const;
+ Expected<DWARFLocationExpressionsVector>
+ getLocations(dwarf::Attribute Attr) const;
+
/// If a DIE represents a subprogram (or inlined subroutine), returns its
/// mangled name (or short name, if mangled is missing). This name may be
/// fetched from specification or abstract origin for this subprogram.
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFLocationExpression.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFLocationExpression.h
index 1522658ead75..35aa1a78e129 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFLocationExpression.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFLocationExpression.h
@@ -41,6 +41,9 @@ inline bool operator!=(const DWARFLocationExpression &L,
raw_ostream &operator<<(raw_ostream &OS, const DWARFLocationExpression &Loc);
+/// Represents a set of absolute location expressions.
+using DWARFLocationExpressionsVector = std::vector<DWARFLocationExpression>;
+
} // end namespace llvm
#endif // LLVM_DEBUGINFO_DWARF_DWARFLOCATIONEXPRESSION_H
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
index d0a8533d1e34..98d7a7ee3cae 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
@@ -439,6 +439,9 @@ class DWARFUnit {
}
Expected<DWARFAddressRangesVector> collectAddressRanges();
+ Expected<DWARFLocationExpressionsVector>
+ findLoclistFromOffset(uint64_t Offset);
+
/// Returns subprogram DIE with address range encompassing the provided
/// address. The pointer is alive as long as parsed compile unit DIEs are not
/// cleared.
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
index 1af51a85d18d..8b84822914d3 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
@@ -151,6 +151,21 @@ bool DWARFLocationTable::dumpLocationList(uint64_t *Offset, raw_ostream &OS,
return true;
}
+Error DWARFLocationTable::visitAbsoluteLocationList(
+ uint64_t Offset, Optional<SectionedAddress> BaseAddr,
+ std::function<Optional<SectionedAddress>(uint32_t)> LookupAddr,
+ function_ref<bool(Expected<DWARFLocationExpression>)> Callback) const {
+ DWARFLocationInterpreter Interp(BaseAddr, std::move(LookupAddr));
+ return visitLocationList(&Offset, [&](const DWARFLocationEntry &E) {
+ Expected<Optional<DWARFLocationExpression>> Loc = Interp.Interpret(E);
+ if (!Loc)
+ return Callback(Loc.takeError());
+ if (*Loc)
+ return Callback(**Loc);
+ return true;
+ });
+}
+
DWARFDebugLoc::LocationList const *
DWARFDebugLoc::getLocationListAtOffset(uint64_t Offset) const {
auto It = partition_point(
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
index a11865e048c5..6cf30270539b 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp
@@ -486,6 +486,27 @@ bool DWARFDie::addressRangeContainsAddress(const uint64_t Address) const {
return false;
}
+Expected<DWARFLocationExpressionsVector>
+DWARFDie::getLocations(dwarf::Attribute Attr) const {
+ Optional<DWARFFormValue> Location = find(Attr);
+ if (!Location)
+ return createStringError(inconvertibleErrorCode(), "No %s",
+ dwarf::AttributeString(Attr).data());
+
+ if (Optional<uint64_t> Off = Location->getAsSectionOffset())
+ return U->findLoclistFromOffset(*Off);
+
+ if (Optional<ArrayRef<uint8_t>> Expr = Location->getAsBlock()) {
+ return DWARFLocationExpressionsVector{
+ DWARFLocationExpression{None, to_vector<4>(*Expr)}};
+ }
+
+ return createStringError(
+ inconvertibleErrorCode(), "Unsupported %s encoding: %s",
+ dwarf::AttributeString(Attr).data(),
+ dwarf::FormEncodingString(Location->getForm()).data());
+}
+
const char *DWARFDie::getSubroutineName(DINameKind Kind) const {
if (!isSubroutineDIE())
return nullptr;
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
index 2eb7d2f945a3..e5d33e136445 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -637,6 +637,30 @@ Expected<DWARFAddressRangesVector> DWARFUnit::collectAddressRanges() {
return *CUDIERangesOrError;
}
+Expected<DWARFLocationExpressionsVector>
+DWARFUnit::findLoclistFromOffset(uint64_t Offset) {
+ DWARFLocationExpressionsVector Result;
+
+ Error InterpretationError = Error::success();
+
+ Error ParseError = getLocationTable().visitAbsoluteLocationList(
+ Offset, getBaseAddress(),
+ [this](uint32_t Index) { return getAddrOffsetSectionItem(Index); },
+ [&](Expected<DWARFLocationExpression> L) {
+ if (L)
+ Result.push_back(std::move(*L));
+ else
+ InterpretationError =
+ joinErrors(L.takeError(), std::move(InterpretationError));
+ return !InterpretationError;
+ });
+
+ if (ParseError || InterpretationError)
+ return joinErrors(std::move(ParseError), std::move(InterpretationError));
+
+ return Result;
+}
+
void DWARFUnit::updateAddressDieMap(DWARFDie Die) {
if (Die.isSubroutineDIE()) {
auto DIERangesOrError = Die.getAddressRanges();
diff --git a/llvm/lib/ObjectYAML/DWARFEmitter.cpp b/llvm/lib/ObjectYAML/DWARFEmitter.cpp
index 2ae66997cf59..b410fed16f09 100644
--- a/llvm/lib/ObjectYAML/DWARFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/DWARFEmitter.cpp
@@ -314,7 +314,10 @@ class DIEFixupVisitor : public DWARFYAML::Visitor {
DIEFixupVisitor(DWARFYAML::Data &DI) : DWARFYAML::Visitor(DI){};
private:
- virtual void onStartCompileUnit(DWARFYAML::Unit &CU) { Length = 7; }
+ virtual void onStartCompileUnit(DWARFYAML::Unit &CU) {
+ // Size of the unit header, excluding the length field itself.
+ Length = CU.Version >= 5 ? 8 : 7;
+ }
virtual void onEndCompileUnit(DWARFYAML::Unit &CU) {
CU.Length.setLength(Length);
diff --git a/llvm/unittests/DebugInfo/DWARF/CMakeLists.txt b/llvm/unittests/DebugInfo/DWARF/CMakeLists.txt
index 2181e0543d04..4fb79b2a96e9 100644
--- a/llvm/unittests/DebugInfo/DWARF/CMakeLists.txt
+++ b/llvm/unittests/DebugInfo/DWARF/CMakeLists.txt
@@ -13,6 +13,7 @@ add_llvm_unittest(DebugInfoDWARFTests
DwarfUtils.cpp
DWARFDebugInfoTest.cpp
DWARFDebugLineTest.cpp
+ DWARFDieTest.cpp
DWARFFormValueTest.cpp
DWARFLocationExpressionTest.cpp
)
diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFDieTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDieTest.cpp
new file mode 100644
index 000000000000..05e8e05b927e
--- /dev/null
+++ b/llvm/unittests/DebugInfo/DWARF/DWARFDieTest.cpp
@@ -0,0 +1,117 @@
+//===- llvm/unittest/DebugInfo/DWARFDieTest.cpp ---------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/ObjectYAML/DWARFEmitter.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::dwarf;
+using object::SectionedAddress;
+
+namespace {
+
+TEST(DWARFLocationTable, getLocations) {
+ const char *yamldata = R"(
+ debug_abbrev:
+ - Code: 0x00000001
+ Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_location
+ Form: DW_FORM_sec_offset
+ - Attribute: DW_AT_data_member_location
+ Form: DW_FORM_exprloc
+ - Attribute: DW_AT_vtable_elem_location
+ Form: DW_FORM_sec_offset
+ - Attribute: DW_AT_call_data_location
+ Form: DW_FORM_sec_offset
+ debug_info:
+ - Length:
+ TotalLength: 0
+ Version: 5
+ UnitType: DW_UT_compile
+ AbbrOffset: 0
+ AddrSize: 4
+ Entries:
+ - AbbrCode: 0x00000001
+ Values:
+ - Value: 12
+ - Value: 0x0000000000000001
+ BlockData: [ 0x47 ]
+ - Value: 20
+ - Value: 25
+ )";
+ Expected<StringMap<std::unique_ptr<MemoryBuffer>>> Sections =
+ DWARFYAML::EmitDebugSections(StringRef(yamldata),
+ /*IsLittleEndian=*/true);
+ ASSERT_THAT_EXPECTED(Sections, Succeeded());
+ std::vector<uint8_t> Loclists{
+ // Header
+ 0, 0, 0, 0, // Length
+ 5, 0, // Version
+ 4, // Address size
+ 0, // Segment selector size
+ 0, 0, 0, 0, // Offset entry count
+ // First location list.
+ DW_LLE_start_length, // First entry
+ 1, 0, 0, 0, // Start offset
+ 2, // Length
+ 0, // Expression length
+ DW_LLE_end_of_list,
+ // Second location list.
+ DW_LLE_startx_length, // First entry
+ 1, // Start index
+ 2, // Length
+ 0, // Expression length
+ DW_LLE_end_of_list,
+ // Third location list.
+ DW_LLE_start_length, // First entry
+ 1, 0, 0, 0, // Start offset
+ 2, // Length
+ 0, // Expression length
+ // end_of_list intentionally missing
+ };
+ Loclists[0] = Loclists.size() - 4;
+ Sections->try_emplace(
+ "debug_loclists",
+ MemoryBuffer::getMemBuffer(toStringRef(Loclists), "debug_loclists",
+ /*RequiresNullTerminator=*/false));
+ std::unique_ptr<DWARFContext> Ctx = DWARFContext::create(*Sections, 8);
+ DWARFCompileUnit *CU = Ctx->getCompileUnitForOffset(0);
+ ASSERT_NE(nullptr, CU);
+ DWARFDie Die = CU->getUnitDIE();
+ ASSERT_TRUE(Die.isValid());
+
+ EXPECT_THAT_EXPECTED(Die.getLocations(DW_AT_location),
+ HasValue(testing::ElementsAre(DWARFLocationExpression{
+ DWARFAddressRange{1, 3}, {}})));
+
+ EXPECT_THAT_EXPECTED(
+ Die.getLocations(DW_AT_data_member_location),
+ HasValue(testing::ElementsAre(DWARFLocationExpression{None, {0x47}})));
+
+ EXPECT_THAT_EXPECTED(
+ Die.getLocations(DW_AT_vtable_elem_location),
+ Failed<ErrorInfoBase>(testing::Property(
+ &ErrorInfoBase::message,
+ "Unable to resolve indirect address 1 for: DW_LLE_startx_length")));
+
+ EXPECT_THAT_EXPECTED(Die.getLocations(DW_AT_call_data_location),
+ Failed<ErrorInfoBase>(testing::Property(
+ &ErrorInfoBase::message, "unexpected end of data")));
+
+ EXPECT_THAT_EXPECTED(
+ Die.getLocations(DW_AT_call_data_value),
+ Failed<ErrorInfoBase>(testing::Property(&ErrorInfoBase::message,
+ "No DW_AT_call_data_value")));
+}
+
+} // end anonymous namespace
More information about the llvm-commits
mailing list