diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h index b86fe593cd52d..f6da96757e290 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h @@ -10,81 +10,60 @@ #define LLVM_DEBUGINFO_DWARF_DWARFDATAEXTRACTOR_H #include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractorSimple.h" +#include "llvm/DebugInfo/DWARF/DWARFObject.h" +#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" #include "llvm/DebugInfo/DWARF/DWARFSection.h" #include "llvm/Support/Compiler.h" -#include "llvm/Support/DataExtractor.h" namespace llvm { -class DWARFObject; -/// A DataExtractor (typically for an in-memory copy of an object-file section) -/// plus a relocation map for that section, if there is one. -class DWARFDataExtractor : public DataExtractor { +/// A DWARFDataExtractor (typically for an in-memory copy of an object-file +/// section) plus a relocation map for that section, if there is one. +class DWARFDataExtractor : public DWARFDataExtractorBase { const DWARFObject *Obj = nullptr; const DWARFSection *Section = nullptr; public: + using DWARFDataExtractorBase::DWARFDataExtractorBase; + /// Constructor for the normal case of extracting data from a DWARF section. /// The DWARFSection's lifetime must be at least as long as the extractor's. DWARFDataExtractor(const DWARFObject &Obj, const DWARFSection &Section, bool IsLittleEndian, uint8_t AddressSize) - : DataExtractor(Section.Data, IsLittleEndian, AddressSize), Obj(&Obj), - Section(&Section) {} - - /// Constructor for cases when there are no relocations. - DWARFDataExtractor(StringRef Data, bool IsLittleEndian, uint8_t AddressSize) - : DataExtractor(Data, IsLittleEndian, AddressSize) {} - DWARFDataExtractor(ArrayRef Data, bool IsLittleEndian, - uint8_t AddressSize) - : DataExtractor( - StringRef(reinterpret_cast(Data.data()), Data.size()), - IsLittleEndian, AddressSize) {} + : DWARFDataExtractorBase(Section.Data, IsLittleEndian, AddressSize), + Obj(&Obj), Section(&Section) {} /// Truncating constructor DWARFDataExtractor(const DWARFDataExtractor &Other, size_t Length) - : DataExtractor(Other.getData().substr(0, Length), Other.isLittleEndian(), - Other.getAddressSize()), + : DWARFDataExtractorBase(Other.getData().substr(0, Length), + Other.isLittleEndian(), Other.getAddressSize()), Obj(Other.Obj), Section(Other.Section) {} - /// Extracts the DWARF "initial length" field, which can either be a 32-bit - /// value smaller than 0xfffffff0, or the value 0xffffffff followed by a - /// 64-bit length. Returns the actual length, and the DWARF format which is - /// encoded in the field. In case of errors, it returns {0, DWARF32} and - /// leaves the offset unchanged. - LLVM_ABI std::pair - getInitialLength(uint64_t *Off, Error *Err = nullptr) const; - - std::pair getInitialLength(Cursor &C) const { - return getInitialLength(&getOffset(C), &getError(C)); - } - /// Extracts a value and applies a relocation to the result if /// one exists for the given offset. - LLVM_ABI uint64_t getRelocatedValue(uint32_t Size, uint64_t *Off, - uint64_t *SectionIndex = nullptr, - Error *Err = nullptr) const; - uint64_t getRelocatedValue(Cursor &C, uint32_t Size, - uint64_t *SectionIndex = nullptr) const { - return getRelocatedValue(Size, &getOffset(C), SectionIndex, &getError(C)); - } + LLVM_ABI uint64_t getRelocatedValueImpl(uint32_t Size, uint64_t *Off, + uint64_t *SecNdx, Error *Err) const { + if (SecNdx) + *SecNdx = object::SectionedAddress::UndefSection; + if (!Section) + return getUnsigned(Off, Size, Err); - /// Extracts an address-sized value and applies a relocation to the result if - /// one exists for the given offset. - uint64_t getRelocatedAddress(uint64_t *Off, uint64_t *SecIx = nullptr) const { - return getRelocatedValue(getAddressSize(), Off, SecIx); - } - uint64_t getRelocatedAddress(Cursor &C, uint64_t *SecIx = nullptr) const { - return getRelocatedValue(getAddressSize(), &getOffset(C), SecIx, - &getError(C)); - } + ErrorAsOutParameter ErrAsOut(Err); + std::optional E = Obj->find(*Section, *Off); + uint64_t LocData = getUnsigned(Off, Size, Err); + if (!E || (Err && *Err)) + return LocData; + if (SecNdx) + *SecNdx = E->SectionIndex; - /// Extracts a DWARF-encoded pointer in \p Offset using \p Encoding. - /// There is a DWARF encoding that uses a PC-relative adjustment. - /// For these values, \p AbsPosOffset is used to fix them, which should - /// reflect the absolute address of this pointer. - LLVM_ABI std::optional - getEncodedPointer(uint64_t *Offset, uint8_t Encoding, - uint64_t AbsPosOffset = 0) const; + uint64_t R = object::resolveRelocation(E->Resolver, E->Reloc, + E->SymbolValue, LocData); + if (E->Reloc2) + R = object::resolveRelocation(E->Resolver, *E->Reloc2, E->SymbolValue2, + R); + return R; + } }; } // end namespace llvm diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDataExtractorSimple.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDataExtractorSimple.h new file mode 100644 index 0000000000000..c931ad196cc41 --- /dev/null +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDataExtractorSimple.h @@ -0,0 +1,192 @@ +//===- DWARFDataExtractorSimple.h -------------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// Non relocating, low-level dwarf-data extractor. Suitable for use from +// libraries that cannot have build-time dependencies on relocation providers. + +#ifndef LLVM_DEBUGINFO_DWARF_DWARFDATAEXTRACTORSIMPLE_H +#define LLVM_DEBUGINFO_DWARF_DWARFDATAEXTRACTORSIMPLE_H + +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/MathExtras.h" + +namespace llvm { + +/// A DataExtractor suitable use for parsing dwarf from memory. Clients use +/// Relocator::getRelocatedValueImpl to relocate values as appropriate. + +template class DWARFDataExtractorBase : public DataExtractor { + +public: + DWARFDataExtractorBase(StringRef Data, bool IsLittleEndian, + uint8_t AddressSize) + : DataExtractor(Data, IsLittleEndian, AddressSize) {} + DWARFDataExtractorBase(ArrayRef Data, bool IsLittleEndian, + uint8_t AddressSize) + : DataExtractor( + StringRef(reinterpret_cast(Data.data()), Data.size()), + IsLittleEndian, AddressSize) {} + + /// Truncating constructor + DWARFDataExtractorBase(const DWARFDataExtractorBase &Other, size_t Length) + : DataExtractor(Other.getData().substr(0, Length), Other.isLittleEndian(), + Other.getAddressSize()) {} + + ~DWARFDataExtractorBase() {} + + /// Extracts a value and returns it as adjusted by the Relocator + uint64_t getRelocatedValue(uint32_t Size, uint64_t *Off, + uint64_t *SectionIndex = nullptr, + Error *Err = nullptr) const { + return static_cast(this)->getRelocatedValueImpl( + Size, Off, SectionIndex, Err); + } + uint64_t getRelocatedValue(Cursor &C, uint32_t Size, + uint64_t *SectionIndex = nullptr) const { + return getRelocatedValue(Size, &getOffset(C), SectionIndex, &getError(C)); + } + + /// Extracts an address-sized value. + uint64_t getRelocatedAddress(uint64_t *Off, uint64_t *SecIx = nullptr) const { + return getRelocatedValue(getAddressSize(), Off, SecIx); + } + uint64_t getRelocatedAddress(Cursor &C, uint64_t *SecIx = nullptr) const { + return getRelocatedValue(getAddressSize(), &getOffset(C), SecIx, + &getError(C)); + } + + /// Extracts the DWARF "initial length" field, which can either be a 32-bit + /// value smaller than 0xfffffff0, or the value 0xffffffff followed by a + /// 64-bit length. Returns the actual length, and the DWARF format which is + /// encoded in the field. In case of errors, it returns {0, DWARF32} and + /// leaves the offset unchanged. + std::pair + getInitialLength(uint64_t *Off, Error *Err = nullptr) const { + ErrorAsOutParameter ErrAsOut(Err); + if (Err && *Err) + return {0, dwarf::DWARF32}; + + Cursor C(*Off); + uint64_t Length = getRelocatedValue(C, 4); + dwarf::DwarfFormat Format = dwarf::DWARF32; + if (Length == dwarf::DW_LENGTH_DWARF64) { + Length = getRelocatedValue(C, 8); + Format = dwarf::DWARF64; + } else if (Length >= dwarf::DW_LENGTH_lo_reserved) { + cantFail(C.takeError()); + if (Err) + *Err = createStringError( + std::errc::invalid_argument, + "unsupported reserved unit length of value 0x%8.8" PRIx64, Length); + return {0, dwarf::DWARF32}; + } + + if (C) { + *Off = C.tell(); + return {Length, Format}; + } + if (Err) + *Err = C.takeError(); + else + consumeError(C.takeError()); + return {0, dwarf::DWARF32}; + } + + std::pair getInitialLength(Cursor &C) const { + return getInitialLength(&getOffset(C), &getError(C)); + } + + /// Extracts a DWARF-encoded pointer in \p Offset using \p Encoding. + /// There is a DWARF encoding that uses a PC-relative adjustment. + /// For these values, \p AbsPosOffset is used to fix them, which should + /// reflect the absolute address of this pointer. + std::optional getEncodedPointer(uint64_t *Offset, uint8_t Encoding, + uint64_t PCRelOffset) const { + if (Encoding == dwarf::DW_EH_PE_omit) + return std::nullopt; + + uint64_t Result = 0; + uint64_t OldOffset = *Offset; + // First get value + switch (Encoding & 0x0F) { + case dwarf::DW_EH_PE_absptr: + switch (getAddressSize()) { + case 2: + case 4: + case 8: + Result = getUnsigned(Offset, getAddressSize()); + break; + default: + return std::nullopt; + } + break; + case dwarf::DW_EH_PE_uleb128: + Result = getULEB128(Offset); + break; + case dwarf::DW_EH_PE_sleb128: + Result = getSLEB128(Offset); + break; + case dwarf::DW_EH_PE_udata2: + Result = getUnsigned(Offset, 2); + break; + case dwarf::DW_EH_PE_udata4: + Result = getUnsigned(Offset, 4); + break; + case dwarf::DW_EH_PE_udata8: + Result = getUnsigned(Offset, 8); + break; + case dwarf::DW_EH_PE_sdata2: + Result = getSigned(Offset, 2); + break; + case dwarf::DW_EH_PE_sdata4: + Result = SignExtend64<32>(getRelocatedValue(4, Offset)); + break; + case dwarf::DW_EH_PE_sdata8: + Result = getRelocatedValue(8, Offset); + break; + default: + return std::nullopt; + } + // Then add relative offset, if required + switch (Encoding & 0x70) { + case dwarf::DW_EH_PE_absptr: + // do nothing + break; + case dwarf::DW_EH_PE_pcrel: + Result += PCRelOffset; + break; + case dwarf::DW_EH_PE_datarel: + case dwarf::DW_EH_PE_textrel: + case dwarf::DW_EH_PE_funcrel: + case dwarf::DW_EH_PE_aligned: + default: + *Offset = OldOffset; + return std::nullopt; + } + + return Result; + } +}; + +class DWARFDataExtractorSimple + : public DWARFDataExtractorBase { + using DWARFDataExtractorBase::DWARFDataExtractorBase; + + uint64_t getRelocatedValueImpl(uint32_t Size, uint64_t *Off, + uint64_t *SectionIndex = nullptr, + Error *Err = nullptr) const { + assert(SectionIndex == nullptr && + "DWARFDATAExtractorSimple cannot take section indices."); + return getUnsigned(Off, Size, Err); + } +}; + +} // end namespace llvm +#endif // LLVM_DEBUGINFO_DWARF_DWARFDATAEXTRACTOR_H diff --git a/llvm/lib/DebugInfo/DWARF/CMakeLists.txt b/llvm/lib/DebugInfo/DWARF/CMakeLists.txt index c4bacbdc484f5..cc9734f9f22be 100644 --- a/llvm/lib/DebugInfo/DWARF/CMakeLists.txt +++ b/llvm/lib/DebugInfo/DWARF/CMakeLists.txt @@ -5,7 +5,6 @@ add_llvm_component_library(LLVMDebugInfoDWARF DWARFCFIProgram.cpp DWARFCompileUnit.cpp DWARFContext.cpp - DWARFDataExtractor.cpp DWARFDebugAbbrev.cpp DWARFDebugAddr.cpp DWARFDebugArangeSet.cpp diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp deleted file mode 100644 index 97434b3cfab82..0000000000000 --- a/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp +++ /dev/null @@ -1,137 +0,0 @@ -//===- DWARFDataExtractor.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/DWARFDataExtractor.h" -#include "llvm/DebugInfo/DWARF/DWARFObject.h" -#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" -#include "llvm/Support/Errc.h" - -using namespace llvm; - -std::pair -DWARFDataExtractor::getInitialLength(uint64_t *Off, Error *Err) const { - ErrorAsOutParameter ErrAsOut(Err); - if (Err && *Err) - return {0, dwarf::DWARF32}; - - Cursor C(*Off); - uint64_t Length = getRelocatedValue(C, 4); - dwarf::DwarfFormat Format = dwarf::DWARF32; - if (Length == dwarf::DW_LENGTH_DWARF64) { - Length = getRelocatedValue(C, 8); - Format = dwarf::DWARF64; - } else if (Length >= dwarf::DW_LENGTH_lo_reserved) { - cantFail(C.takeError()); - if (Err) - *Err = createStringError( - errc::invalid_argument, - "unsupported reserved unit length of value 0x%8.8" PRIx64, Length); - return {0, dwarf::DWARF32}; - } - - if (C) { - *Off = C.tell(); - return {Length, Format}; - } - if (Err) - *Err = C.takeError(); - else - consumeError(C.takeError()); - return {0, dwarf::DWARF32}; -} - -uint64_t DWARFDataExtractor::getRelocatedValue(uint32_t Size, uint64_t *Off, - uint64_t *SecNdx, - Error *Err) const { - if (SecNdx) - *SecNdx = object::SectionedAddress::UndefSection; - if (!Section) - return getUnsigned(Off, Size, Err); - - ErrorAsOutParameter ErrAsOut(Err); - std::optional E = Obj->find(*Section, *Off); - uint64_t LocData = getUnsigned(Off, Size, Err); - if (!E || (Err && *Err)) - return LocData; - if (SecNdx) - *SecNdx = E->SectionIndex; - - uint64_t R = - object::resolveRelocation(E->Resolver, E->Reloc, E->SymbolValue, LocData); - if (E->Reloc2) - R = object::resolveRelocation(E->Resolver, *E->Reloc2, E->SymbolValue2, R); - return R; -} - -std::optional -DWARFDataExtractor::getEncodedPointer(uint64_t *Offset, uint8_t Encoding, - uint64_t PCRelOffset) const { - if (Encoding == dwarf::DW_EH_PE_omit) - return std::nullopt; - - uint64_t Result = 0; - uint64_t OldOffset = *Offset; - // First get value - switch (Encoding & 0x0F) { - case dwarf::DW_EH_PE_absptr: - switch (getAddressSize()) { - case 2: - case 4: - case 8: - Result = getUnsigned(Offset, getAddressSize()); - break; - default: - return std::nullopt; - } - break; - case dwarf::DW_EH_PE_uleb128: - Result = getULEB128(Offset); - break; - case dwarf::DW_EH_PE_sleb128: - Result = getSLEB128(Offset); - break; - case dwarf::DW_EH_PE_udata2: - Result = getUnsigned(Offset, 2); - break; - case dwarf::DW_EH_PE_udata4: - Result = getUnsigned(Offset, 4); - break; - case dwarf::DW_EH_PE_udata8: - Result = getUnsigned(Offset, 8); - break; - case dwarf::DW_EH_PE_sdata2: - Result = getSigned(Offset, 2); - break; - case dwarf::DW_EH_PE_sdata4: - Result = SignExtend64<32>(getRelocatedValue(4, Offset)); - break; - case dwarf::DW_EH_PE_sdata8: - Result = getRelocatedValue(8, Offset); - break; - default: - return std::nullopt; - } - // Then add relative offset, if required - switch (Encoding & 0x70) { - case dwarf::DW_EH_PE_absptr: - // do nothing - break; - case dwarf::DW_EH_PE_pcrel: - Result += PCRelOffset; - break; - case dwarf::DW_EH_PE_datarel: - case dwarf::DW_EH_PE_textrel: - case dwarf::DW_EH_PE_funcrel: - case dwarf::DW_EH_PE_aligned: - default: - *Offset = OldOffset; - return std::nullopt; - } - - return Result; -}