Path: blob/main/contrib/llvm-project/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
35269 views
//===- DWARFDebugLoc.cpp --------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"9#include "llvm/ADT/StringRef.h"10#include "llvm/BinaryFormat/Dwarf.h"11#include "llvm/DebugInfo/DIContext.h"12#include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"13#include "llvm/DebugInfo/DWARF/DWARFExpression.h"14#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"15#include "llvm/DebugInfo/DWARF/DWARFLocationExpression.h"16#include "llvm/DebugInfo/DWARF/DWARFUnit.h"17#include "llvm/Support/Format.h"18#include "llvm/Support/raw_ostream.h"19#include <algorithm>20#include <cinttypes>21#include <cstdint>2223using namespace llvm;24using object::SectionedAddress;2526namespace llvm {27class DWARFObject;28}2930namespace {31class DWARFLocationInterpreter {32std::optional<object::SectionedAddress> Base;33std::function<std::optional<object::SectionedAddress>(uint32_t)> LookupAddr;3435public:36DWARFLocationInterpreter(37std::optional<object::SectionedAddress> Base,38std::function<std::optional<object::SectionedAddress>(uint32_t)>39LookupAddr)40: Base(Base), LookupAddr(std::move(LookupAddr)) {}4142Expected<std::optional<DWARFLocationExpression>>43Interpret(const DWARFLocationEntry &E);44};45} // namespace4647static Error createResolverError(uint32_t Index, unsigned Kind) {48return make_error<ResolverError>(Index, (dwarf::LoclistEntries)Kind);49}5051Expected<std::optional<DWARFLocationExpression>>52DWARFLocationInterpreter::Interpret(const DWARFLocationEntry &E) {53switch (E.Kind) {54case dwarf::DW_LLE_end_of_list:55return std::nullopt;56case dwarf::DW_LLE_base_addressx: {57Base = LookupAddr(E.Value0);58if (!Base)59return createResolverError(E.Value0, E.Kind);60return std::nullopt;61}62case dwarf::DW_LLE_startx_endx: {63std::optional<SectionedAddress> LowPC = LookupAddr(E.Value0);64if (!LowPC)65return createResolverError(E.Value0, E.Kind);66std::optional<SectionedAddress> HighPC = LookupAddr(E.Value1);67if (!HighPC)68return createResolverError(E.Value1, E.Kind);69return DWARFLocationExpression{70DWARFAddressRange{LowPC->Address, HighPC->Address, LowPC->SectionIndex},71E.Loc};72}73case dwarf::DW_LLE_startx_length: {74std::optional<SectionedAddress> LowPC = LookupAddr(E.Value0);75if (!LowPC)76return createResolverError(E.Value0, E.Kind);77return DWARFLocationExpression{DWARFAddressRange{LowPC->Address,78LowPC->Address + E.Value1,79LowPC->SectionIndex},80E.Loc};81}82case dwarf::DW_LLE_offset_pair: {83if (!Base) {84return createStringError(inconvertibleErrorCode(),85"Unable to resolve location list offset pair: "86"Base address not defined");87}88DWARFAddressRange Range{Base->Address + E.Value0, Base->Address + E.Value1,89Base->SectionIndex};90if (Range.SectionIndex == SectionedAddress::UndefSection)91Range.SectionIndex = E.SectionIndex;92return DWARFLocationExpression{Range, E.Loc};93}94case dwarf::DW_LLE_default_location:95return DWARFLocationExpression{std::nullopt, E.Loc};96case dwarf::DW_LLE_base_address:97Base = SectionedAddress{E.Value0, E.SectionIndex};98return std::nullopt;99case dwarf::DW_LLE_start_end:100return DWARFLocationExpression{101DWARFAddressRange{E.Value0, E.Value1, E.SectionIndex}, E.Loc};102case dwarf::DW_LLE_start_length:103return DWARFLocationExpression{104DWARFAddressRange{E.Value0, E.Value0 + E.Value1, E.SectionIndex},105E.Loc};106default:107llvm_unreachable("unreachable locations list kind");108}109}110111static void dumpExpression(raw_ostream &OS, DIDumpOptions DumpOpts,112ArrayRef<uint8_t> Data, bool IsLittleEndian,113unsigned AddressSize, DWARFUnit *U) {114DWARFDataExtractor Extractor(Data, IsLittleEndian, AddressSize);115// Note. We do not pass any format to DWARFExpression, even if the116// corresponding unit is known. For now, there is only one operation,117// DW_OP_call_ref, which depends on the format; it is rarely used, and118// is unexpected in location tables.119DWARFExpression(Extractor, AddressSize).print(OS, DumpOpts, U);120}121122bool DWARFLocationTable::dumpLocationList(123uint64_t *Offset, raw_ostream &OS, std::optional<SectionedAddress> BaseAddr,124const DWARFObject &Obj, DWARFUnit *U, DIDumpOptions DumpOpts,125unsigned Indent) const {126DWARFLocationInterpreter Interp(127BaseAddr, [U](uint32_t Index) -> std::optional<SectionedAddress> {128if (U)129return U->getAddrOffsetSectionItem(Index);130return std::nullopt;131});132OS << format("0x%8.8" PRIx64 ": ", *Offset);133Error E = visitLocationList(Offset, [&](const DWARFLocationEntry &E) {134Expected<std::optional<DWARFLocationExpression>> Loc = Interp.Interpret(E);135if (!Loc || DumpOpts.DisplayRawContents)136dumpRawEntry(E, OS, Indent, DumpOpts, Obj);137if (Loc && *Loc) {138OS << "\n";139OS.indent(Indent);140if (DumpOpts.DisplayRawContents)141OS << " => ";142143DIDumpOptions RangeDumpOpts(DumpOpts);144RangeDumpOpts.DisplayRawContents = false;145if (Loc.get()->Range)146Loc.get()->Range->dump(OS, Data.getAddressSize(), RangeDumpOpts, &Obj);147else148OS << "<default>";149}150if (!Loc)151consumeError(Loc.takeError());152153if (E.Kind != dwarf::DW_LLE_base_address &&154E.Kind != dwarf::DW_LLE_base_addressx &&155E.Kind != dwarf::DW_LLE_end_of_list) {156OS << ": ";157dumpExpression(OS, DumpOpts, E.Loc, Data.isLittleEndian(),158Data.getAddressSize(), U);159}160return true;161});162if (E) {163DumpOpts.RecoverableErrorHandler(std::move(E));164return false;165}166return true;167}168169Error DWARFLocationTable::visitAbsoluteLocationList(170uint64_t Offset, std::optional<SectionedAddress> BaseAddr,171std::function<std::optional<SectionedAddress>(uint32_t)> LookupAddr,172function_ref<bool(Expected<DWARFLocationExpression>)> Callback) const {173DWARFLocationInterpreter Interp(BaseAddr, std::move(LookupAddr));174return visitLocationList(&Offset, [&](const DWARFLocationEntry &E) {175Expected<std::optional<DWARFLocationExpression>> Loc = Interp.Interpret(E);176if (!Loc)177return Callback(Loc.takeError());178if (*Loc)179return Callback(**Loc);180return true;181});182}183184void DWARFDebugLoc::dump(raw_ostream &OS, const DWARFObject &Obj,185DIDumpOptions DumpOpts,186std::optional<uint64_t> DumpOffset) const {187auto BaseAddr = std::nullopt;188unsigned Indent = 12;189if (DumpOffset) {190dumpLocationList(&*DumpOffset, OS, BaseAddr, Obj, nullptr, DumpOpts,191Indent);192} else {193uint64_t Offset = 0;194StringRef Separator;195bool CanContinue = true;196while (CanContinue && Data.isValidOffset(Offset)) {197OS << Separator;198Separator = "\n";199200CanContinue = dumpLocationList(&Offset, OS, BaseAddr, Obj, nullptr,201DumpOpts, Indent);202OS << '\n';203}204}205}206207Error DWARFDebugLoc::visitLocationList(208uint64_t *Offset,209function_ref<bool(const DWARFLocationEntry &)> Callback) const {210DataExtractor::Cursor C(*Offset);211while (true) {212uint64_t SectionIndex;213uint64_t Value0 = Data.getRelocatedAddress(C);214uint64_t Value1 = Data.getRelocatedAddress(C, &SectionIndex);215216DWARFLocationEntry E;217218// The end of any given location list is marked by an end of list entry,219// which consists of a 0 for the beginning address offset and a 0 for the220// ending address offset. A beginning offset of 0xff...f marks the base221// address selection entry.222if (Value0 == 0 && Value1 == 0) {223E.Kind = dwarf::DW_LLE_end_of_list;224} else if (Value0 == (Data.getAddressSize() == 4 ? -1U : -1ULL)) {225E.Kind = dwarf::DW_LLE_base_address;226E.Value0 = Value1;227E.SectionIndex = SectionIndex;228} else {229E.Kind = dwarf::DW_LLE_offset_pair;230E.Value0 = Value0;231E.Value1 = Value1;232E.SectionIndex = SectionIndex;233unsigned Bytes = Data.getU16(C);234// A single location description describing the location of the object...235Data.getU8(C, E.Loc, Bytes);236}237238if (!C)239return C.takeError();240if (!Callback(E) || E.Kind == dwarf::DW_LLE_end_of_list)241break;242}243*Offset = C.tell();244return Error::success();245}246247void DWARFDebugLoc::dumpRawEntry(const DWARFLocationEntry &Entry,248raw_ostream &OS, unsigned Indent,249DIDumpOptions DumpOpts,250const DWARFObject &Obj) const {251uint64_t Value0, Value1;252switch (Entry.Kind) {253case dwarf::DW_LLE_base_address:254Value0 = Data.getAddressSize() == 4 ? -1U : -1ULL;255Value1 = Entry.Value0;256break;257case dwarf::DW_LLE_offset_pair:258Value0 = Entry.Value0;259Value1 = Entry.Value1;260break;261case dwarf::DW_LLE_end_of_list:262return;263default:264llvm_unreachable("Not possible in DWARF4!");265}266OS << '\n';267OS.indent(Indent);268OS << '(' << format_hex(Value0, 2 + Data.getAddressSize() * 2) << ", "269<< format_hex(Value1, 2 + Data.getAddressSize() * 2) << ')';270DWARFFormValue::dumpAddressSection(Obj, OS, DumpOpts, Entry.SectionIndex);271}272273Error DWARFDebugLoclists::visitLocationList(274uint64_t *Offset, function_ref<bool(const DWARFLocationEntry &)> F) const {275276DataExtractor::Cursor C(*Offset);277bool Continue = true;278while (Continue) {279DWARFLocationEntry E;280E.Kind = Data.getU8(C);281switch (E.Kind) {282case dwarf::DW_LLE_end_of_list:283break;284case dwarf::DW_LLE_base_addressx:285E.Value0 = Data.getULEB128(C);286break;287case dwarf::DW_LLE_startx_endx:288E.Value0 = Data.getULEB128(C);289E.Value1 = Data.getULEB128(C);290break;291case dwarf::DW_LLE_startx_length:292E.Value0 = Data.getULEB128(C);293// Pre-DWARF 5 has different interpretation of the length field. We have294// to support both pre- and standartized styles for the compatibility.295if (Version < 5)296E.Value1 = Data.getU32(C);297else298E.Value1 = Data.getULEB128(C);299break;300case dwarf::DW_LLE_offset_pair:301E.Value0 = Data.getULEB128(C);302E.Value1 = Data.getULEB128(C);303E.SectionIndex = SectionedAddress::UndefSection;304break;305case dwarf::DW_LLE_default_location:306break;307case dwarf::DW_LLE_base_address:308E.Value0 = Data.getRelocatedAddress(C, &E.SectionIndex);309break;310case dwarf::DW_LLE_start_end:311E.Value0 = Data.getRelocatedAddress(C, &E.SectionIndex);312E.Value1 = Data.getRelocatedAddress(C);313break;314case dwarf::DW_LLE_start_length:315E.Value0 = Data.getRelocatedAddress(C, &E.SectionIndex);316E.Value1 = Data.getULEB128(C);317break;318default:319cantFail(C.takeError());320return createStringError(errc::illegal_byte_sequence,321"LLE of kind %x not supported", (int)E.Kind);322}323324if (E.Kind != dwarf::DW_LLE_base_address &&325E.Kind != dwarf::DW_LLE_base_addressx &&326E.Kind != dwarf::DW_LLE_end_of_list) {327unsigned Bytes = Version >= 5 ? Data.getULEB128(C) : Data.getU16(C);328// A single location description describing the location of the object...329Data.getU8(C, E.Loc, Bytes);330}331332if (!C)333return C.takeError();334Continue = F(E) && E.Kind != dwarf::DW_LLE_end_of_list;335}336*Offset = C.tell();337return Error::success();338}339340void DWARFDebugLoclists::dumpRawEntry(const DWARFLocationEntry &Entry,341raw_ostream &OS, unsigned Indent,342DIDumpOptions DumpOpts,343const DWARFObject &Obj) const {344size_t MaxEncodingStringLength = 0;345#define HANDLE_DW_LLE(ID, NAME) \346MaxEncodingStringLength = std::max(MaxEncodingStringLength, \347dwarf::LocListEncodingString(ID).size());348#include "llvm/BinaryFormat/Dwarf.def"349350OS << "\n";351OS.indent(Indent);352StringRef EncodingString = dwarf::LocListEncodingString(Entry.Kind);353// Unsupported encodings should have been reported during parsing.354assert(!EncodingString.empty() && "Unknown loclist entry encoding");355OS << format("%-*s(", MaxEncodingStringLength, EncodingString.data());356unsigned FieldSize = 2 + 2 * Data.getAddressSize();357switch (Entry.Kind) {358case dwarf::DW_LLE_end_of_list:359case dwarf::DW_LLE_default_location:360break;361case dwarf::DW_LLE_startx_endx:362case dwarf::DW_LLE_startx_length:363case dwarf::DW_LLE_offset_pair:364case dwarf::DW_LLE_start_end:365case dwarf::DW_LLE_start_length:366OS << format_hex(Entry.Value0, FieldSize) << ", "367<< format_hex(Entry.Value1, FieldSize);368break;369case dwarf::DW_LLE_base_addressx:370case dwarf::DW_LLE_base_address:371OS << format_hex(Entry.Value0, FieldSize);372break;373}374OS << ')';375switch (Entry.Kind) {376case dwarf::DW_LLE_base_address:377case dwarf::DW_LLE_start_end:378case dwarf::DW_LLE_start_length:379DWARFFormValue::dumpAddressSection(Obj, OS, DumpOpts, Entry.SectionIndex);380break;381default:382break;383}384}385386void DWARFDebugLoclists::dumpRange(uint64_t StartOffset, uint64_t Size,387raw_ostream &OS, const DWARFObject &Obj,388DIDumpOptions DumpOpts) {389if (!Data.isValidOffsetForDataOfSize(StartOffset, Size)) {390OS << "Invalid dump range\n";391return;392}393uint64_t Offset = StartOffset;394StringRef Separator;395bool CanContinue = true;396while (CanContinue && Offset < StartOffset + Size) {397OS << Separator;398Separator = "\n";399400CanContinue = dumpLocationList(&Offset, OS, /*BaseAddr=*/std::nullopt, Obj,401nullptr, DumpOpts, /*Indent=*/12);402OS << '\n';403}404}405406void llvm::ResolverError::log(raw_ostream &OS) const {407OS << format("unable to resolve indirect address %u for: %s", Index,408dwarf::LocListEncodingString(Kind).data());409}410411char llvm::ResolverError::ID;412413414