Files
clang-p2996/llvm/include/llvm/DebugInfo/DWARF/LowLevel/DWARFExpression.h
Sterling-Augustine cbf781f0bd [NFC][DebugInfo][DWARF] Create new low-level dwarf library (#145081)
This is the culmination of a series of changes described in [1].
    
Although somewhat large by line count, it is almost entirely mechanical,
creating a new library in DebugInfo/DWARF/LowLevel. This new library has
very minimal dependencies, allowing it to be used from more places than
the normal DebugInfo/DWARF library--in particular from MC.
    
I am happy to put it in another location, or to structure it differently
if that makes sense. Some have suggested in BinaryFormat, but it is not
a great fit there. But if that makes more sense to the reviewers, I can
do that.
 
Another possibility would be to use pass-through headers to allow
clients who don't care to depend only on DebugInfo/DWARF. This would be
a much less invasive change, and perhaps easier for clients. But also a
system that hides details.

Either way, I'm open.

1.
https://discourse.llvm.org/t/rfc-debuginfo-dwarf-refactor-into-to-lower-and-higher-level-libraries/86665/2
2025-06-26 11:23:46 -07:00

174 lines
5.5 KiB
C++

//===--- DWARFExpression.h - DWARF Expression handling ----------*- 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
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_DWARF_DWARFEXPRESSION_H
#define LLVM_DEBUGINFO_DWARF_DWARFEXPRESSION_H
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/iterator.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/DataExtractor.h"
namespace llvm {
class DWARFUnit;
struct DIDumpOptions;
class MCRegisterInfo;
class raw_ostream;
class DWARFExpression {
public:
class iterator;
/// This class represents an Operation in the Expression.
///
/// An Operation can be in Error state (check with isError()). This
/// means that it couldn't be decoded successfully and if it is the
/// case, all others fields contain undefined values.
class Operation {
public:
/// Size and signedness of expression operations' operands.
enum Encoding : uint8_t {
Size1 = 0,
Size2 = 1,
Size4 = 2,
Size8 = 3,
SizeLEB = 4,
SizeAddr = 5,
SizeRefAddr = 6,
SizeBlock = 7, ///< Preceding operand contains block size
BaseTypeRef = 8,
/// The operand is a ULEB128 encoded SubOpcode. This is only valid
/// for the first operand of an operation.
SizeSubOpLEB = 9,
WasmLocationArg = 30,
SignBit = 0x80,
SignedSize1 = SignBit | Size1,
SignedSize2 = SignBit | Size2,
SignedSize4 = SignBit | Size4,
SignedSize8 = SignBit | Size8,
SignedSizeLEB = SignBit | SizeLEB,
};
enum DwarfVersion : uint8_t {
DwarfNA, ///< Serves as a marker for unused entries
Dwarf2 = 2,
Dwarf3,
Dwarf4,
Dwarf5
};
/// Description of the encoding of one expression Op.
struct Description {
DwarfVersion Version; ///< Dwarf version where the Op was introduced.
SmallVector<Encoding> Op; ///< Encoding for Op operands.
template <typename... Ts>
Description(DwarfVersion Version, Ts... Op)
: Version(Version), Op{Op...} {}
Description() : Description(DwarfNA) {}
~Description() = default;
};
private:
friend class DWARFExpression::iterator;
friend class DWARFVerifier;
uint8_t Opcode; ///< The Op Opcode, DW_OP_<something>.
Description Desc;
bool Error = false;
uint64_t EndOffset;
SmallVector<uint64_t> Operands;
SmallVector<uint64_t> OperandEndOffsets;
public:
const Description &getDescription() const { return Desc; }
uint8_t getCode() const { return Opcode; }
LLVM_ABI std::optional<unsigned> getSubCode() const;
uint64_t getNumOperands() const { return Operands.size(); }
ArrayRef<uint64_t> getRawOperands() const { return Operands; };
uint64_t getRawOperand(unsigned Idx) const { return Operands[Idx]; }
ArrayRef<uint64_t> getOperandEndOffsets() const {
return OperandEndOffsets;
}
uint64_t getOperandEndOffset(unsigned Idx) const {
return OperandEndOffsets[Idx];
}
uint64_t getEndOffset() const { return EndOffset; }
bool isError() const { return Error; }
private:
LLVM_ABI bool extract(DataExtractor Data, uint8_t AddressSize,
uint64_t Offset,
std::optional<dwarf::DwarfFormat> Format);
};
/// An iterator to go through the expression operations.
class iterator
: public iterator_facade_base<iterator, std::forward_iterator_tag,
const Operation> {
friend class DWARFExpression;
const DWARFExpression *Expr;
uint64_t Offset;
Operation Op;
iterator(const DWARFExpression *Expr, uint64_t Offset)
: Expr(Expr), Offset(Offset) {
Op.Error =
Offset >= Expr->Data.getData().size() ||
!Op.extract(Expr->Data, Expr->AddressSize, Offset, Expr->Format);
}
public:
iterator &operator++() {
Offset = Op.isError() ? Expr->Data.getData().size() : Op.EndOffset;
Op.Error =
Offset >= Expr->Data.getData().size() ||
!Op.extract(Expr->Data, Expr->AddressSize, Offset, Expr->Format);
return *this;
}
const Operation &operator*() const { return Op; }
iterator skipBytes(uint64_t Add) const {
return iterator(Expr, Op.EndOffset + Add);
}
// Comparison operators are provided out of line.
friend bool operator==(const iterator &, const iterator &);
};
DWARFExpression(DataExtractor Data, uint8_t AddressSize,
std::optional<dwarf::DwarfFormat> Format = std::nullopt)
: Data(Data), AddressSize(AddressSize), Format(Format) {
assert(AddressSize == 8 || AddressSize == 4 || AddressSize == 2);
}
iterator begin() const { return iterator(this, 0); }
iterator end() const { return iterator(this, Data.getData().size()); }
LLVM_ABI bool operator==(const DWARFExpression &RHS) const;
StringRef getData() const { return Data.getData(); }
friend class DWARFVerifier;
private:
DataExtractor Data;
uint8_t AddressSize;
std::optional<dwarf::DwarfFormat> Format;
};
inline bool operator==(const DWARFExpression::iterator &LHS,
const DWARFExpression::iterator &RHS) {
return LHS.Expr == RHS.Expr && LHS.Offset == RHS.Offset;
}
} // end namespace llvm
#endif // LLVM_DEBUGINFO_DWARF_DWARFEXPRESSION_H