[llvm] a03435e - Recommit "[DWARF] Add an api to get "interpreted" location lists"

Pavel Labath via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 20 07:23:27 PST 2019


Author: Pavel Labath
Date: 2019-11-20T16:24:11+01:00
New Revision: a03435ec8e219e236331780626351c74a95f1b6e

URL: https://github.com/llvm/llvm-project/commit/a03435ec8e219e236331780626351c74a95f1b6e
DIFF: https://github.com/llvm/llvm-project/commit/a03435ec8e219e236331780626351c74a95f1b6e.diff

LOG: Recommit "[DWARF] Add an api to get "interpreted" location lists"

This recommits 089c0f581492cd6e2a3d2927be3fbf60ea2d7e62, which was
reverted due to failing tests on big endian machines. It includes a fix
which I believe (I don't have BE machine) should fix this issue. The fix
consists of correcting the invocation DWARFYAML::EmitDebugSections,
which was missing one (default) function arguments, and so didn't
actually force the little-endian mode.

The original commit message follows.

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..53124925a895
--- /dev/null
+++ b/llvm/unittests/DebugInfo/DWARF/DWARFDieTest.cpp
@@ -0,0 +1,118 @@
+//===- 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(DWARFDie, 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), /*ApplyFixups=*/true,
+                                   /*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, 4, /*isLittleEndian=*/true);
+  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