diff options
Diffstat (limited to 'llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp')
-rw-r--r-- | llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp | 524 |
1 files changed, 297 insertions, 227 deletions
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp index 4f7b01130a47..0c5f9a9c54ec 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp @@ -22,6 +22,89 @@ #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 createStringError(errc::invalid_argument, + "Unable to resolve indirect address %u for: %s", + Index, dwarf::LocListEncodingString(Kind).data()); +} + +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"); + } +} // When directly dumping the .debug_loc without a compile unit, we have to guess // at the DWARF version. This only affects DW_OP_call_ref, which is a rare @@ -35,126 +118,180 @@ static void dumpExpression(raw_ostream &OS, ArrayRef<uint8_t> Data, DWARFExpression(Extractor, dwarf::DWARF_VERSION, AddressSize).print(OS, MRI, U); } -void DWARFDebugLoc::LocationList::dump(raw_ostream &OS, uint64_t BaseAddress, - bool IsLittleEndian, - unsigned AddressSize, - const MCRegisterInfo *MRI, DWARFUnit *U, - DIDumpOptions DumpOpts, - unsigned Indent) const { - for (const Entry &E : Entries) { - OS << '\n'; +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, E.Loc, Data.isLittleEndian(), Data.getAddressSize(), + MRI, U); + } + return true; + }); + if (E) { + OS << "\n"; OS.indent(Indent); - OS << format("[0x%*.*" PRIx64 ", ", AddressSize * 2, AddressSize * 2, - BaseAddress + E.Begin); - OS << format(" 0x%*.*" PRIx64 ")", AddressSize * 2, AddressSize * 2, - BaseAddress + E.End); - OS << ": "; - - dumpExpression(OS, E.Loc, IsLittleEndian, AddressSize, MRI, U); + OS << "error: " << toString(std::move(E)); + return false; } + return true; } -DWARFDebugLoc::LocationList const * -DWARFDebugLoc::getLocationListAtOffset(uint64_t Offset) const { - auto It = partition_point( - Locations, [=](const LocationList &L) { return L.Offset < Offset; }); - if (It != Locations.end() && It->Offset == Offset) - return &(*It); - return nullptr; +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, DIDumpOptions DumpOpts, - Optional<uint64_t> Offset) const { - auto DumpLocationList = [&](const LocationList &L) { - OS << format("0x%8.8" PRIx64 ": ", L.Offset); - L.dump(OS, 0, IsLittleEndian, AddressSize, MRI, nullptr, DumpOpts, 12); - OS << "\n"; - }; - - if (Offset) { - if (auto *L = getLocationListAtOffset(*Offset)) - DumpLocationList(*L); - return; - } - - for (const LocationList &L : Locations) { - DumpLocationList(L); - if (&L != &Locations.back()) +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'; + } } } -Expected<DWARFDebugLoc::LocationList> -DWARFDebugLoc::parseOneLocationList(const DWARFDataExtractor &Data, - uint64_t *Offset) { - LocationList LL; - LL.Offset = *Offset; - AddressSize = Data.getAddressSize(); +Error DWARFDebugLoc::visitLocationList( + uint64_t *Offset, + function_ref<bool(const DWARFLocationEntry &)> Callback) const { DataExtractor::Cursor C(*Offset); - - // 2.6.2 Location Lists - // A location list entry consists of: while (true) { - Entry E; - - // 1. A beginning address offset. ... - E.Begin = Data.getRelocatedAddress(C); + uint64_t SectionIndex; + uint64_t Value0 = Data.getRelocatedAddress(C); + uint64_t Value1 = Data.getRelocatedAddress(C, &SectionIndex); - // 2. An ending address offset. ... - E.End = Data.getRelocatedAddress(C); - - if (Error Err = C.takeError()) - return std::move(Err); + 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. - if (E.Begin == 0 && E.End == 0) { - *Offset = C.tell(); - return LL; - } - - if (E.Begin != (AddressSize == 4 ? -1U : -1ULL)) { + // 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); } - LL.Entries.push_back(std::move(E)); + 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::parse(const DWARFDataExtractor &data) { - IsLittleEndian = data.isLittleEndian(); - AddressSize = data.getAddressSize(); - - uint64_t Offset = 0; - while (Offset < data.getData().size()) { - if (auto LL = parseOneLocationList(data, &Offset)) - Locations.push_back(std::move(*LL)); - else { - logAllUnhandledErrors(LL.takeError(), WithColor::error()); - break; - } +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: + Value0 = Value1 = 0; + 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); } -Expected<DWARFDebugLoclists::LocationList> -DWARFDebugLoclists::parseOneLocationList(const DataExtractor &Data, - uint64_t *Offset, unsigned Version) { - LocationList LL; - LL.Offset = *Offset; - DataExtractor::Cursor C(*Offset); +Error DWARFDebugLoclists::visitLocationList( + uint64_t *Offset, function_ref<bool(const DWARFLocationEntry &)> F) const { - // dwarf::DW_LLE_end_of_list_entry is 0 and indicates the end of the list. - while (auto Kind = Data.getU8(C)) { - Entry E; - E.Kind = Kind; - E.Offset = C.tell() - 1; - switch (Kind) { + 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 @@ -164,176 +301,109 @@ DWARFDebugLoclists::parseOneLocationList(const DataExtractor &Data, else E.Value1 = Data.getULEB128(C); break; - case dwarf::DW_LLE_start_length: - E.Value0 = Data.getAddress(C); - 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.getAddress(C); + 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)Kind); + "LLE of kind %x not supported", (int)E.Kind); } - if (Kind != dwarf::DW_LLE_base_address && - Kind != dwarf::DW_LLE_base_addressx) { + 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); } - LL.Entries.push_back(std::move(E)); + if (!C) + return C.takeError(); + Continue = F(E) && E.Kind != dwarf::DW_LLE_end_of_list; } - if (Error Err = C.takeError()) - return std::move(Err); - Entry E; - E.Kind = dwarf::DW_LLE_end_of_list; - E.Offset = C.tell() - 1; - LL.Entries.push_back(E); *Offset = C.tell(); - return LL; -} - -void DWARFDebugLoclists::parse(DataExtractor data, uint64_t Offset, uint64_t EndOffset, uint16_t Version) { - IsLittleEndian = data.isLittleEndian(); - AddressSize = data.getAddressSize(); - - while (Offset < EndOffset) { - if (auto LL = parseOneLocationList(data, &Offset, Version)) - Locations.push_back(std::move(*LL)); - else { - logAllUnhandledErrors(LL.takeError(), WithColor::error()); - return; - } - } -} - -DWARFDebugLoclists::LocationList const * -DWARFDebugLoclists::getLocationListAtOffset(uint64_t Offset) const { - auto It = partition_point( - Locations, [=](const LocationList &L) { return L.Offset < Offset; }); - if (It != Locations.end() && It->Offset == Offset) - return &(*It); - return nullptr; + return Error::success(); } -void DWARFDebugLoclists::Entry::dump(raw_ostream &OS, uint64_t &BaseAddr, - bool IsLittleEndian, unsigned AddressSize, - const MCRegisterInfo *MRI, DWARFUnit *U, - DIDumpOptions DumpOpts, unsigned Indent, - size_t MaxEncodingStringLength) const { - if (DumpOpts.Verbose) { - OS << "\n"; - OS.indent(Indent); - auto EncodingString = dwarf::LocListEncodingString(Kind); - // Unsupported encodings should have been reported during parsing. - assert(!EncodingString.empty() && "Unknown loclist entry encoding"); - OS << format("%s%*c", EncodingString.data(), - MaxEncodingStringLength - EncodingString.size() + 1, '('); - switch (Kind) { - case dwarf::DW_LLE_startx_length: - case dwarf::DW_LLE_start_length: - case dwarf::DW_LLE_offset_pair: - OS << format("0x%*.*" PRIx64 ", 0x%*.*" PRIx64, AddressSize * 2, - AddressSize * 2, Value0, AddressSize * 2, AddressSize * 2, - Value1); - break; - case dwarf::DW_LLE_base_addressx: - case dwarf::DW_LLE_base_address: - OS << format("0x%*.*" PRIx64, AddressSize * 2, AddressSize * 2, - Value0); - break; - case dwarf::DW_LLE_end_of_list: - break; - } - OS << ')'; - } - auto PrintPrefix = [&] { - OS << "\n"; - OS.indent(Indent); - if (DumpOpts.Verbose) - OS << format("%*s", MaxEncodingStringLength, (const char *)"=> "); - }; - switch (Kind) { - case dwarf::DW_LLE_startx_length: - PrintPrefix(); - OS << "Addr idx " << Value0 << " (w/ length " << Value1 << "): "; - break; - case dwarf::DW_LLE_start_length: - PrintPrefix(); - DWARFAddressRange(Value0, Value0 + Value1) - .dump(OS, AddressSize, DumpOpts); - OS << ": "; +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: - PrintPrefix(); - DWARFAddressRange(BaseAddr + Value0, BaseAddr + Value1) - .dump(OS, AddressSize, DumpOpts); - OS << ": "; + 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: - if (!DumpOpts.Verbose) - return; - break; - case dwarf::DW_LLE_end_of_list: - if (!DumpOpts.Verbose) - return; + case dwarf::DW_LLE_base_address: + OS << format_hex(Entry.Value0, FieldSize); break; + } + OS << ')'; + switch (Entry.Kind) { case dwarf::DW_LLE_base_address: - BaseAddr = Value0; - if (!DumpOpts.Verbose) - return; + case dwarf::DW_LLE_start_end: + case dwarf::DW_LLE_start_length: + DWARFFormValue::dumpAddressSection(Obj, OS, DumpOpts, Entry.SectionIndex); break; default: - llvm_unreachable("unreachable locations list kind"); + break; } - - dumpExpression(OS, Loc, IsLittleEndian, AddressSize, MRI, U); -} -void DWARFDebugLoclists::LocationList::dump(raw_ostream &OS, uint64_t BaseAddr, - bool IsLittleEndian, - unsigned AddressSize, - const MCRegisterInfo *MRI, - DWARFUnit *U, - DIDumpOptions DumpOpts, - unsigned Indent) const { - size_t MaxEncodingStringLength = 0; - if (DumpOpts.Verbose) - for (const auto &Entry : Entries) - MaxEncodingStringLength = - std::max(MaxEncodingStringLength, - dwarf::LocListEncodingString(Entry.Kind).size()); - - for (const Entry &E : Entries) - E.dump(OS, BaseAddr, IsLittleEndian, AddressSize, MRI, U, DumpOpts, Indent, - MaxEncodingStringLength); } -void DWARFDebugLoclists::dump(raw_ostream &OS, uint64_t BaseAddr, - const MCRegisterInfo *MRI, DIDumpOptions DumpOpts, - Optional<uint64_t> Offset) const { - auto DumpLocationList = [&](const LocationList &L) { - OS << format("0x%8.8" PRIx64 ": ", L.Offset); - L.dump(OS, BaseAddr, IsLittleEndian, AddressSize, MRI, nullptr, DumpOpts, - /*Indent=*/12); - OS << "\n"; - }; - - if (Offset) { - if (auto *L = getLocationListAtOffset(*Offset)) - DumpLocationList(*L); +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; } - - for (const LocationList &L : Locations) { - DumpLocationList(L); - if (&L != &Locations.back()) - OS << '\n'; + 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'; } } |