Files
clang-p2996/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
David Blaikie 4f60a42878 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)
2021-12-16 22:24:32 -08:00

412 lines
14 KiB
C++

//===- DWARFDebugLoc.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/DebugInfo/DWARF/DWARFDebugLoc.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cinttypes>
#include <cstdint>
using namespace llvm;
using object::SectionedAddress;
namespace {
class DWARFLocationInterpreter {
Optional<object::SectionedAddress> Base;
std::function<Optional<object::SectionedAddress>(uint32_t)> LookupAddr;
public:
DWARFLocationInterpreter(
Optional<object::SectionedAddress> Base,
std::function<Optional<object::SectionedAddress>(uint32_t)> LookupAddr)
: Base(Base), LookupAddr(std::move(LookupAddr)) {}
Expected<Optional<DWARFLocationExpression>>
Interpret(const DWARFLocationEntry &E);
};
} // namespace
static Error createResolverError(uint32_t Index, unsigned Kind) {
return make_error<ResolverError>(Index, (dwarf::LoclistEntries)Kind);
}
Expected<Optional<DWARFLocationExpression>>
DWARFLocationInterpreter::Interpret(const DWARFLocationEntry &E) {
switch (E.Kind) {
case dwarf::DW_LLE_end_of_list:
return None;
case dwarf::DW_LLE_base_addressx: {
Base = LookupAddr(E.Value0);
if (!Base)
return createResolverError(E.Value0, E.Kind);
return None;
}
case dwarf::DW_LLE_startx_endx: {
Optional<SectionedAddress> LowPC = LookupAddr(E.Value0);
if (!LowPC)
return createResolverError(E.Value0, E.Kind);
Optional<SectionedAddress> HighPC = LookupAddr(E.Value1);
if (!HighPC)
return createResolverError(E.Value1, E.Kind);
return DWARFLocationExpression{
DWARFAddressRange{LowPC->Address, HighPC->Address, LowPC->SectionIndex},
E.Loc};
}
case dwarf::DW_LLE_startx_length: {
Optional<SectionedAddress> LowPC = LookupAddr(E.Value0);
if (!LowPC)
return createResolverError(E.Value0, E.Kind);
return DWARFLocationExpression{DWARFAddressRange{LowPC->Address,
LowPC->Address + E.Value1,
LowPC->SectionIndex},
E.Loc};
}
case dwarf::DW_LLE_offset_pair: {
if (!Base) {
return createStringError(inconvertibleErrorCode(),
"Unable to resolve location list offset pair: "
"Base address not defined");
}
DWARFAddressRange Range{Base->Address + E.Value0, Base->Address + E.Value1,
Base->SectionIndex};
if (Range.SectionIndex == SectionedAddress::UndefSection)
Range.SectionIndex = E.SectionIndex;
return DWARFLocationExpression{Range, E.Loc};
}
case dwarf::DW_LLE_default_location:
return DWARFLocationExpression{None, E.Loc};
case dwarf::DW_LLE_base_address:
Base = SectionedAddress{E.Value0, E.SectionIndex};
return None;
case dwarf::DW_LLE_start_end:
return DWARFLocationExpression{
DWARFAddressRange{E.Value0, E.Value1, E.SectionIndex}, E.Loc};
case dwarf::DW_LLE_start_length:
return DWARFLocationExpression{
DWARFAddressRange{E.Value0, E.Value0 + E.Value1, E.SectionIndex},
E.Loc};
default:
llvm_unreachable("unreachable locations list kind");
}
}
static void dumpExpression(raw_ostream &OS, DIDumpOptions DumpOpts,
ArrayRef<uint8_t> Data, bool IsLittleEndian,
unsigned AddressSize, const MCRegisterInfo *MRI,
DWARFUnit *U) {
DWARFDataExtractor Extractor(Data, IsLittleEndian, AddressSize);
// Note. We do not pass any format to DWARFExpression, even if the
// corresponding unit is known. For now, there is only one operation,
// DW_OP_call_ref, which depends on the format; it is rarely used, and
// is unexpected in location tables.
DWARFExpression(Extractor, AddressSize).print(OS, DumpOpts, MRI, U);
}
bool DWARFLocationTable::dumpLocationList(uint64_t *Offset, raw_ostream &OS,
Optional<SectionedAddress> BaseAddr,
const MCRegisterInfo *MRI,
const DWARFObject &Obj, DWARFUnit *U,
DIDumpOptions DumpOpts,
unsigned Indent) const {
DWARFLocationInterpreter Interp(
BaseAddr, [U](uint32_t Index) -> Optional<SectionedAddress> {
if (U)
return U->getAddrOffsetSectionItem(Index);
return None;
});
OS << format("0x%8.8" PRIx64 ": ", *Offset);
Error E = visitLocationList(Offset, [&](const DWARFLocationEntry &E) {
Expected<Optional<DWARFLocationExpression>> Loc = Interp.Interpret(E);
if (!Loc || DumpOpts.DisplayRawContents)
dumpRawEntry(E, OS, Indent, DumpOpts, Obj);
if (Loc && *Loc) {
OS << "\n";
OS.indent(Indent);
if (DumpOpts.DisplayRawContents)
OS << " => ";
DIDumpOptions RangeDumpOpts(DumpOpts);
RangeDumpOpts.DisplayRawContents = false;
if (Loc.get()->Range)
Loc.get()->Range->dump(OS, Data.getAddressSize(), RangeDumpOpts, &Obj);
else
OS << "<default>";
}
if (!Loc)
consumeError(Loc.takeError());
if (E.Kind != dwarf::DW_LLE_base_address &&
E.Kind != dwarf::DW_LLE_base_addressx &&
E.Kind != dwarf::DW_LLE_end_of_list) {
OS << ": ";
dumpExpression(OS, DumpOpts, E.Loc, Data.isLittleEndian(),
Data.getAddressSize(), MRI, U);
}
return true;
});
if (E) {
DumpOpts.RecoverableErrorHandler(std::move(E));
return false;
}
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;
});
}
void DWARFDebugLoc::dump(raw_ostream &OS, const MCRegisterInfo *MRI,
const DWARFObject &Obj, DIDumpOptions DumpOpts,
Optional<uint64_t> DumpOffset) const {
auto BaseAddr = None;
unsigned Indent = 12;
if (DumpOffset) {
dumpLocationList(&*DumpOffset, OS, BaseAddr, MRI, Obj, nullptr, DumpOpts,
Indent);
} else {
uint64_t Offset = 0;
StringRef Separator;
bool CanContinue = true;
while (CanContinue && Data.isValidOffset(Offset)) {
OS << Separator;
Separator = "\n";
CanContinue = dumpLocationList(&Offset, OS, BaseAddr, MRI, Obj, nullptr,
DumpOpts, Indent);
OS << '\n';
}
}
}
Error DWARFDebugLoc::visitLocationList(
uint64_t *Offset,
function_ref<bool(const DWARFLocationEntry &)> Callback) const {
DataExtractor::Cursor C(*Offset);
while (true) {
uint64_t SectionIndex;
uint64_t Value0 = Data.getRelocatedAddress(C);
uint64_t Value1 = Data.getRelocatedAddress(C, &SectionIndex);
DWARFLocationEntry E;
// The end of any given location list is marked by an end of list entry,
// which consists of a 0 for the beginning address offset and a 0 for the
// ending address offset. A beginning offset of 0xff...f marks the base
// address selection entry.
if (Value0 == 0 && Value1 == 0) {
E.Kind = dwarf::DW_LLE_end_of_list;
} else if (Value0 == (Data.getAddressSize() == 4 ? -1U : -1ULL)) {
E.Kind = dwarf::DW_LLE_base_address;
E.Value0 = Value1;
E.SectionIndex = SectionIndex;
} else {
E.Kind = dwarf::DW_LLE_offset_pair;
E.Value0 = Value0;
E.Value1 = Value1;
E.SectionIndex = SectionIndex;
unsigned Bytes = Data.getU16(C);
// A single location description describing the location of the object...
Data.getU8(C, E.Loc, Bytes);
}
if (!C)
return C.takeError();
if (!Callback(E) || E.Kind == dwarf::DW_LLE_end_of_list)
break;
}
*Offset = C.tell();
return Error::success();
}
void DWARFDebugLoc::dumpRawEntry(const DWARFLocationEntry &Entry,
raw_ostream &OS, unsigned Indent,
DIDumpOptions DumpOpts,
const DWARFObject &Obj) const {
uint64_t Value0, Value1;
switch (Entry.Kind) {
case dwarf::DW_LLE_base_address:
Value0 = Data.getAddressSize() == 4 ? -1U : -1ULL;
Value1 = Entry.Value0;
break;
case dwarf::DW_LLE_offset_pair:
Value0 = Entry.Value0;
Value1 = Entry.Value1;
break;
case dwarf::DW_LLE_end_of_list:
return;
default:
llvm_unreachable("Not possible in DWARF4!");
}
OS << '\n';
OS.indent(Indent);
OS << '(' << format_hex(Value0, 2 + Data.getAddressSize() * 2) << ", "
<< format_hex(Value1, 2 + Data.getAddressSize() * 2) << ')';
DWARFFormValue::dumpAddressSection(Obj, OS, DumpOpts, Entry.SectionIndex);
}
Error DWARFDebugLoclists::visitLocationList(
uint64_t *Offset, function_ref<bool(const DWARFLocationEntry &)> F) const {
DataExtractor::Cursor C(*Offset);
bool Continue = true;
while (Continue) {
DWARFLocationEntry E;
E.Kind = Data.getU8(C);
switch (E.Kind) {
case dwarf::DW_LLE_end_of_list:
break;
case dwarf::DW_LLE_base_addressx:
E.Value0 = Data.getULEB128(C);
break;
case dwarf::DW_LLE_startx_endx:
E.Value0 = Data.getULEB128(C);
E.Value1 = Data.getULEB128(C);
break;
case dwarf::DW_LLE_startx_length:
E.Value0 = Data.getULEB128(C);
// Pre-DWARF 5 has different interpretation of the length field. We have
// to support both pre- and standartized styles for the compatibility.
if (Version < 5)
E.Value1 = Data.getU32(C);
else
E.Value1 = Data.getULEB128(C);
break;
case dwarf::DW_LLE_offset_pair:
E.Value0 = Data.getULEB128(C);
E.Value1 = Data.getULEB128(C);
E.SectionIndex = SectionedAddress::UndefSection;
break;
case dwarf::DW_LLE_default_location:
break;
case dwarf::DW_LLE_base_address:
E.Value0 = Data.getRelocatedAddress(C, &E.SectionIndex);
break;
case dwarf::DW_LLE_start_end:
E.Value0 = Data.getRelocatedAddress(C, &E.SectionIndex);
E.Value1 = Data.getRelocatedAddress(C);
break;
case dwarf::DW_LLE_start_length:
E.Value0 = Data.getRelocatedAddress(C, &E.SectionIndex);
E.Value1 = Data.getULEB128(C);
break;
default:
cantFail(C.takeError());
return createStringError(errc::illegal_byte_sequence,
"LLE of kind %x not supported", (int)E.Kind);
}
if (E.Kind != dwarf::DW_LLE_base_address &&
E.Kind != dwarf::DW_LLE_base_addressx &&
E.Kind != dwarf::DW_LLE_end_of_list) {
unsigned Bytes = Version >= 5 ? Data.getULEB128(C) : Data.getU16(C);
// A single location description describing the location of the object...
Data.getU8(C, E.Loc, Bytes);
}
if (!C)
return C.takeError();
Continue = F(E) && E.Kind != dwarf::DW_LLE_end_of_list;
}
*Offset = C.tell();
return Error::success();
}
void DWARFDebugLoclists::dumpRawEntry(const DWARFLocationEntry &Entry,
raw_ostream &OS, unsigned Indent,
DIDumpOptions DumpOpts,
const DWARFObject &Obj) const {
size_t MaxEncodingStringLength = 0;
#define HANDLE_DW_LLE(ID, NAME) \
MaxEncodingStringLength = std::max(MaxEncodingStringLength, \
dwarf::LocListEncodingString(ID).size());
#include "llvm/BinaryFormat/Dwarf.def"
OS << "\n";
OS.indent(Indent);
StringRef EncodingString = dwarf::LocListEncodingString(Entry.Kind);
// Unsupported encodings should have been reported during parsing.
assert(!EncodingString.empty() && "Unknown loclist entry encoding");
OS << format("%-*s(", MaxEncodingStringLength, EncodingString.data());
unsigned FieldSize = 2 + 2 * Data.getAddressSize();
switch (Entry.Kind) {
case dwarf::DW_LLE_end_of_list:
case dwarf::DW_LLE_default_location:
break;
case dwarf::DW_LLE_startx_endx:
case dwarf::DW_LLE_startx_length:
case dwarf::DW_LLE_offset_pair:
case dwarf::DW_LLE_start_end:
case dwarf::DW_LLE_start_length:
OS << format_hex(Entry.Value0, FieldSize) << ", "
<< format_hex(Entry.Value1, FieldSize);
break;
case dwarf::DW_LLE_base_addressx:
case dwarf::DW_LLE_base_address:
OS << format_hex(Entry.Value0, FieldSize);
break;
}
OS << ')';
switch (Entry.Kind) {
case dwarf::DW_LLE_base_address:
case dwarf::DW_LLE_start_end:
case dwarf::DW_LLE_start_length:
DWARFFormValue::dumpAddressSection(Obj, OS, DumpOpts, Entry.SectionIndex);
break;
default:
break;
}
}
void DWARFDebugLoclists::dumpRange(uint64_t StartOffset, uint64_t Size,
raw_ostream &OS, const MCRegisterInfo *MRI,
const DWARFObject &Obj,
DIDumpOptions DumpOpts) {
if (!Data.isValidOffsetForDataOfSize(StartOffset, Size)) {
OS << "Invalid dump range\n";
return;
}
uint64_t Offset = StartOffset;
StringRef Separator;
bool CanContinue = true;
while (CanContinue && Offset < StartOffset + Size) {
OS << Separator;
Separator = "\n";
CanContinue = dumpLocationList(&Offset, OS, /*BaseAddr=*/None, MRI, Obj,
nullptr, DumpOpts, /*Indent=*/12);
OS << '\n';
}
}
void llvm::ResolverError::log(raw_ostream &OS) const {
OS << format("unable to resolve indirect address %u for: %s", Index,
dwarf::LocListEncodingString(Kind).data());
}
char llvm::ResolverError::ID;