mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-15 12:09:51 +00:00
[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
This commit is contained in:
parent
979592a6f7
commit
089c0f5814
@ -63,6 +63,11 @@ public:
|
|||||||
const MCRegisterInfo *MRI, DWARFUnit *U,
|
const MCRegisterInfo *MRI, DWARFUnit *U,
|
||||||
DIDumpOptions DumpOpts, unsigned Indent) const;
|
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:
|
protected:
|
||||||
DWARFDataExtractor Data;
|
DWARFDataExtractor Data;
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"
|
#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"
|
||||||
#include "llvm/DebugInfo/DWARF/DWARFAttribute.h"
|
#include "llvm/DebugInfo/DWARF/DWARFAttribute.h"
|
||||||
#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
|
#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
|
||||||
|
#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
@ -231,6 +232,9 @@ public:
|
|||||||
|
|
||||||
bool addressRangeContainsAddress(const uint64_t Address) const;
|
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
|
/// If a DIE represents a subprogram (or inlined subroutine), returns its
|
||||||
/// mangled name (or short name, if mangled is missing). This name may be
|
/// mangled name (or short name, if mangled is missing). This name may be
|
||||||
/// fetched from specification or abstract origin for this subprogram.
|
/// fetched from specification or abstract origin for this subprogram.
|
||||||
|
@ -41,6 +41,9 @@ inline bool operator!=(const DWARFLocationExpression &L,
|
|||||||
|
|
||||||
raw_ostream &operator<<(raw_ostream &OS, const DWARFLocationExpression &Loc);
|
raw_ostream &operator<<(raw_ostream &OS, const DWARFLocationExpression &Loc);
|
||||||
|
|
||||||
|
/// Represents a set of absolute location expressions.
|
||||||
|
using DWARFLocationExpressionsVector = std::vector<DWARFLocationExpression>;
|
||||||
|
|
||||||
} // end namespace llvm
|
} // end namespace llvm
|
||||||
|
|
||||||
#endif // LLVM_DEBUGINFO_DWARF_DWARFLOCATIONEXPRESSION_H
|
#endif // LLVM_DEBUGINFO_DWARF_DWARFLOCATIONEXPRESSION_H
|
||||||
|
@ -439,6 +439,9 @@ public:
|
|||||||
}
|
}
|
||||||
Expected<DWARFAddressRangesVector> collectAddressRanges();
|
Expected<DWARFAddressRangesVector> collectAddressRanges();
|
||||||
|
|
||||||
|
Expected<DWARFLocationExpressionsVector>
|
||||||
|
findLoclistFromOffset(uint64_t Offset);
|
||||||
|
|
||||||
/// Returns subprogram DIE with address range encompassing the provided
|
/// Returns subprogram DIE with address range encompassing the provided
|
||||||
/// address. The pointer is alive as long as parsed compile unit DIEs are not
|
/// address. The pointer is alive as long as parsed compile unit DIEs are not
|
||||||
/// cleared.
|
/// cleared.
|
||||||
|
@ -151,6 +151,21 @@ bool DWARFLocationTable::dumpLocationList(uint64_t *Offset, raw_ostream &OS,
|
|||||||
return true;
|
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::LocationList const *
|
||||||
DWARFDebugLoc::getLocationListAtOffset(uint64_t Offset) const {
|
DWARFDebugLoc::getLocationListAtOffset(uint64_t Offset) const {
|
||||||
auto It = partition_point(
|
auto It = partition_point(
|
||||||
|
@ -486,6 +486,27 @@ bool DWARFDie::addressRangeContainsAddress(const uint64_t Address) const {
|
|||||||
return false;
|
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 {
|
const char *DWARFDie::getSubroutineName(DINameKind Kind) const {
|
||||||
if (!isSubroutineDIE())
|
if (!isSubroutineDIE())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -637,6 +637,30 @@ Expected<DWARFAddressRangesVector> DWARFUnit::collectAddressRanges() {
|
|||||||
return *CUDIERangesOrError;
|
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) {
|
void DWARFUnit::updateAddressDieMap(DWARFDie Die) {
|
||||||
if (Die.isSubroutineDIE()) {
|
if (Die.isSubroutineDIE()) {
|
||||||
auto DIERangesOrError = Die.getAddressRanges();
|
auto DIERangesOrError = Die.getAddressRanges();
|
||||||
|
@ -314,7 +314,10 @@ public:
|
|||||||
DIEFixupVisitor(DWARFYAML::Data &DI) : DWARFYAML::Visitor(DI){};
|
DIEFixupVisitor(DWARFYAML::Data &DI) : DWARFYAML::Visitor(DI){};
|
||||||
|
|
||||||
private:
|
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) {
|
virtual void onEndCompileUnit(DWARFYAML::Unit &CU) {
|
||||||
CU.Length.setLength(Length);
|
CU.Length.setLength(Length);
|
||||||
|
@ -13,6 +13,7 @@ add_llvm_unittest(DebugInfoDWARFTests
|
|||||||
DwarfUtils.cpp
|
DwarfUtils.cpp
|
||||||
DWARFDebugInfoTest.cpp
|
DWARFDebugInfoTest.cpp
|
||||||
DWARFDebugLineTest.cpp
|
DWARFDebugLineTest.cpp
|
||||||
|
DWARFDieTest.cpp
|
||||||
DWARFFormValueTest.cpp
|
DWARFFormValueTest.cpp
|
||||||
DWARFLocationExpressionTest.cpp
|
DWARFLocationExpressionTest.cpp
|
||||||
)
|
)
|
||||||
|
117
llvm/unittests/DebugInfo/DWARF/DWARFDieTest.cpp
Normal file
117
llvm/unittests/DebugInfo/DWARF/DWARFDieTest.cpp
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user