diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h index e94fa7bf5590f..4394e46806d84 100644 --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDataExtractor.h @@ -10,79 +10,46 @@ #define LLVM_DEBUGINFO_DWARF_DWARFDATAEXTRACTOR_H #include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractorSimple.h" #include "llvm/DebugInfo/DWARF/DWARFSection.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 DWARFDataExtractorSimple (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 DWARFDataExtractorSimple { const DWARFObject *Obj = nullptr; const DWARFSection *Section = nullptr; public: + using DWARFDataExtractorSimple::DWARFDataExtractorSimple; + /// 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) {} + : DWARFDataExtractorSimple(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()), + : DWARFDataExtractorSimple(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. - 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. uint64_t getRelocatedValue(uint32_t Size, uint64_t *Off, uint64_t *SectionIndex = nullptr, - Error *Err = nullptr) const; + Error *Err = nullptr) const override; + uint64_t getRelocatedValue(Cursor &C, uint32_t Size, - uint64_t *SectionIndex = nullptr) const { + uint64_t *SectionIndex = nullptr) const override { return getRelocatedValue(Size, &getOffset(C), SectionIndex, &getError(C)); } - - /// 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)); - } - - /// 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 AbsPosOffset = 0) const; }; } // 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..b6f1c081f83e8 --- /dev/null +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDataExtractorSimple.h @@ -0,0 +1,88 @@ +//===- 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" + +namespace llvm { + +/// A DataExtractor suitable use for parsing dwarf from memory with minimal +/// dwarf context--no sections and no objects. getRelocated* functions +/// return raw values. + +class DWARFDataExtractorSimple : public DataExtractor { + +public: + DWARFDataExtractorSimple(StringRef Data, bool IsLittleEndian, + uint8_t AddressSize) + : DataExtractor(Data, IsLittleEndian, AddressSize) {} + DWARFDataExtractorSimple(ArrayRef Data, bool IsLittleEndian, + uint8_t AddressSize) + : DataExtractor( + StringRef(reinterpret_cast(Data.data()), Data.size()), + IsLittleEndian, AddressSize) {} + + /// Truncating constructor + DWARFDataExtractorSimple(const DWARFDataExtractorSimple &Other, size_t Length) + : DataExtractor(Other.getData().substr(0, Length), Other.isLittleEndian(), + Other.getAddressSize()) {} + + virtual ~DWARFDataExtractorSimple() = default; + + /// 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; + + std::pair getInitialLength(Cursor &C) const { + return getInitialLength(&getOffset(C), &getError(C)); + } + + /// Extracts a value and returns it unrelocated. Named such to implement the + /// required interface. + virtual uint64_t getRelocatedValue(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); + } + virtual 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 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 AbsPosOffset = 0) const; +}; + +} // 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 e565821cf2942..2dbe7f66446b4 100644 --- a/llvm/lib/DebugInfo/DWARF/CMakeLists.txt +++ b/llvm/lib/DebugInfo/DWARF/CMakeLists.txt @@ -5,6 +5,7 @@ add_llvm_component_library(LLVMDebugInfoDWARF DWARFCompileUnit.cpp DWARFContext.cpp DWARFDataExtractor.cpp + DWARFDataExtractorSimple.cpp DWARFDebugAbbrev.cpp DWARFDebugAddr.cpp DWARFDebugArangeSet.cpp diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp index 97434b3cfab82..5b4ae615ae565 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp @@ -13,38 +13,6 @@ 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 { @@ -67,71 +35,3 @@ uint64_t DWARFDataExtractor::getRelocatedValue(uint32_t Size, uint64_t *Off, 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; -} diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDataExtractorSimple.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDataExtractorSimple.cpp new file mode 100644 index 0000000000000..382d234d996f0 --- /dev/null +++ b/llvm/lib/DebugInfo/DWARF/DWARFDataExtractorSimple.cpp @@ -0,0 +1,113 @@ +//===- DWARFDataExtractorSimple.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/DWARFDataExtractorSimple.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/MathExtras.h" + +using namespace llvm; + +std::pair +DWARFDataExtractorSimple::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}; +} + +std::optional +DWARFDataExtractorSimple::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; +}