
Reapply "[NFC][DebugInfo][DWARF] Create new low-level dwarf library (#… (#145959) This reapplies cbf781f0bdf2f680abbe784faedeefd6f84c246e, with fixes for the shared-library build and the unconventional sanitizer-runtime build. Original Description: 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. 1. https://discourse.llvm.org/t/rfc-debuginfo-dwarf-refactor-into-to-lower-and-higher-level-libraries/86665/2
254 lines
9.8 KiB
C++
254 lines
9.8 KiB
C++
//===-- DWARFExpression.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/LowLevel/DWARFExpression.h"
|
|
#include "llvm/ADT/SmallString.h"
|
|
#include "llvm/Support/Format.h"
|
|
#include <cassert>
|
|
#include <cstdint>
|
|
#include <vector>
|
|
|
|
using namespace llvm;
|
|
using namespace dwarf;
|
|
|
|
namespace llvm {
|
|
|
|
typedef DWARFExpression::Operation Op;
|
|
typedef Op::Description Desc;
|
|
|
|
static std::vector<Desc> getOpDescriptions() {
|
|
std::vector<Desc> Descriptions;
|
|
Descriptions.resize(0xff);
|
|
Descriptions[DW_OP_addr] = Desc(Op::Dwarf2, Op::SizeAddr);
|
|
Descriptions[DW_OP_deref] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_const1u] = Desc(Op::Dwarf2, Op::Size1);
|
|
Descriptions[DW_OP_const1s] = Desc(Op::Dwarf2, Op::SignedSize1);
|
|
Descriptions[DW_OP_const2u] = Desc(Op::Dwarf2, Op::Size2);
|
|
Descriptions[DW_OP_const2s] = Desc(Op::Dwarf2, Op::SignedSize2);
|
|
Descriptions[DW_OP_const4u] = Desc(Op::Dwarf2, Op::Size4);
|
|
Descriptions[DW_OP_const4s] = Desc(Op::Dwarf2, Op::SignedSize4);
|
|
Descriptions[DW_OP_const8u] = Desc(Op::Dwarf2, Op::Size8);
|
|
Descriptions[DW_OP_const8s] = Desc(Op::Dwarf2, Op::SignedSize8);
|
|
Descriptions[DW_OP_constu] = Desc(Op::Dwarf2, Op::SizeLEB);
|
|
Descriptions[DW_OP_consts] = Desc(Op::Dwarf2, Op::SignedSizeLEB);
|
|
Descriptions[DW_OP_dup] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_drop] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_over] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_pick] = Desc(Op::Dwarf2, Op::Size1);
|
|
Descriptions[DW_OP_swap] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_rot] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_xderef] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_abs] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_and] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_div] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_minus] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_mod] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_mul] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_neg] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_not] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_or] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_plus] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_plus_uconst] = Desc(Op::Dwarf2, Op::SizeLEB);
|
|
Descriptions[DW_OP_shl] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_shr] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_shra] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_xor] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_bra] = Desc(Op::Dwarf2, Op::SignedSize2);
|
|
Descriptions[DW_OP_eq] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_ge] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_gt] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_le] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_lt] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_ne] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_skip] = Desc(Op::Dwarf2, Op::SignedSize2);
|
|
for (uint16_t LA = DW_OP_lit0; LA <= DW_OP_lit31; ++LA)
|
|
Descriptions[LA] = Desc(Op::Dwarf2);
|
|
for (uint16_t LA = DW_OP_reg0; LA <= DW_OP_reg31; ++LA)
|
|
Descriptions[LA] = Desc(Op::Dwarf2);
|
|
for (uint16_t LA = DW_OP_breg0; LA <= DW_OP_breg31; ++LA)
|
|
Descriptions[LA] = Desc(Op::Dwarf2, Op::SignedSizeLEB);
|
|
Descriptions[DW_OP_regx] = Desc(Op::Dwarf2, Op::SizeLEB);
|
|
Descriptions[DW_OP_fbreg] = Desc(Op::Dwarf2, Op::SignedSizeLEB);
|
|
Descriptions[DW_OP_bregx] = Desc(Op::Dwarf2, Op::SizeLEB, Op::SignedSizeLEB);
|
|
Descriptions[DW_OP_piece] = Desc(Op::Dwarf2, Op::SizeLEB);
|
|
Descriptions[DW_OP_deref_size] = Desc(Op::Dwarf2, Op::Size1);
|
|
Descriptions[DW_OP_xderef_size] = Desc(Op::Dwarf2, Op::Size1);
|
|
Descriptions[DW_OP_nop] = Desc(Op::Dwarf2);
|
|
Descriptions[DW_OP_push_object_address] = Desc(Op::Dwarf3);
|
|
Descriptions[DW_OP_call2] = Desc(Op::Dwarf3, Op::Size2);
|
|
Descriptions[DW_OP_call4] = Desc(Op::Dwarf3, Op::Size4);
|
|
Descriptions[DW_OP_call_ref] = Desc(Op::Dwarf3, Op::SizeRefAddr);
|
|
Descriptions[DW_OP_form_tls_address] = Desc(Op::Dwarf3);
|
|
Descriptions[DW_OP_call_frame_cfa] = Desc(Op::Dwarf3);
|
|
Descriptions[DW_OP_bit_piece] = Desc(Op::Dwarf3, Op::SizeLEB, Op::SizeLEB);
|
|
Descriptions[DW_OP_implicit_value] =
|
|
Desc(Op::Dwarf4, Op::SizeLEB, Op::SizeBlock);
|
|
Descriptions[DW_OP_stack_value] = Desc(Op::Dwarf4);
|
|
Descriptions[DW_OP_implicit_pointer] =
|
|
Desc(Op::Dwarf5, Op::SizeRefAddr, Op::SignedSizeLEB);
|
|
Descriptions[DW_OP_addrx] = Desc(Op::Dwarf5, Op::SizeLEB);
|
|
Descriptions[DW_OP_constx] = Desc(Op::Dwarf5, Op::SizeLEB);
|
|
Descriptions[DW_OP_entry_value] = Desc(Op::Dwarf5, Op::SizeLEB);
|
|
Descriptions[DW_OP_convert] = Desc(Op::Dwarf5, Op::BaseTypeRef);
|
|
Descriptions[DW_OP_regval_type] =
|
|
Desc(Op::Dwarf5, Op::SizeLEB, Op::BaseTypeRef);
|
|
Descriptions[DW_OP_WASM_location] =
|
|
Desc(Op::Dwarf4, Op::SizeLEB, Op::WasmLocationArg);
|
|
Descriptions[DW_OP_GNU_push_tls_address] = Desc(Op::Dwarf3);
|
|
Descriptions[DW_OP_GNU_addr_index] = Desc(Op::Dwarf4, Op::SizeLEB);
|
|
Descriptions[DW_OP_GNU_const_index] = Desc(Op::Dwarf4, Op::SizeLEB);
|
|
Descriptions[DW_OP_GNU_entry_value] = Desc(Op::Dwarf4, Op::SizeLEB);
|
|
Descriptions[DW_OP_GNU_implicit_pointer] =
|
|
Desc(Op::Dwarf4, Op::SizeRefAddr, Op::SignedSizeLEB);
|
|
// This Description acts as a marker that getSubOpDesc must be called
|
|
// to fetch the final Description for the operation. Each such final
|
|
// Description must share the same first SizeSubOpLEB operand.
|
|
Descriptions[DW_OP_LLVM_user] = Desc(Op::Dwarf5, Op::SizeSubOpLEB);
|
|
return Descriptions;
|
|
}
|
|
|
|
static Desc getDescImpl(ArrayRef<Desc> Descriptions, unsigned Opcode) {
|
|
// Handle possible corrupted or unsupported operation.
|
|
if (Opcode >= Descriptions.size())
|
|
return {};
|
|
return Descriptions[Opcode];
|
|
}
|
|
|
|
static Desc getOpDesc(unsigned Opcode) {
|
|
static std::vector<Desc> Descriptions = getOpDescriptions();
|
|
return getDescImpl(Descriptions, Opcode);
|
|
}
|
|
|
|
static std::vector<Desc> getSubOpDescriptions() {
|
|
static constexpr unsigned LlvmUserDescriptionsSize = 1
|
|
#define HANDLE_DW_OP_LLVM_USEROP(ID, NAME) +1
|
|
#include "llvm/BinaryFormat/Dwarf.def"
|
|
;
|
|
std::vector<Desc> Descriptions;
|
|
Descriptions.resize(LlvmUserDescriptionsSize);
|
|
Descriptions[DW_OP_LLVM_nop] = Desc(Op::Dwarf5, Op::SizeSubOpLEB);
|
|
return Descriptions;
|
|
}
|
|
|
|
static Desc getSubOpDesc(unsigned Opcode, unsigned SubOpcode) {
|
|
assert(Opcode == DW_OP_LLVM_user);
|
|
static std::vector<Desc> Descriptions = getSubOpDescriptions();
|
|
return getDescImpl(Descriptions, SubOpcode);
|
|
}
|
|
|
|
bool DWARFExpression::Operation::extract(DataExtractor Data,
|
|
uint8_t AddressSize, uint64_t Offset,
|
|
std::optional<DwarfFormat> Format) {
|
|
EndOffset = Offset;
|
|
Opcode = Data.getU8(&Offset);
|
|
|
|
Desc = getOpDesc(Opcode);
|
|
if (Desc.Version == Operation::DwarfNA)
|
|
return false;
|
|
|
|
Operands.resize(Desc.Op.size());
|
|
OperandEndOffsets.resize(Desc.Op.size());
|
|
for (unsigned Operand = 0; Operand < Desc.Op.size(); ++Operand) {
|
|
unsigned Size = Desc.Op[Operand];
|
|
unsigned Signed = Size & Operation::SignBit;
|
|
|
|
switch (Size & ~Operation::SignBit) {
|
|
case Operation::SizeSubOpLEB:
|
|
assert(Operand == 0 && "SubOp operand must be the first operand");
|
|
Operands[Operand] = Data.getULEB128(&Offset);
|
|
Desc = getSubOpDesc(Opcode, Operands[Operand]);
|
|
if (Desc.Version == Operation::DwarfNA)
|
|
return false;
|
|
assert(Desc.Op[Operand] == Operation::SizeSubOpLEB &&
|
|
"SizeSubOpLEB Description must begin with SizeSubOpLEB operand");
|
|
break;
|
|
case Operation::Size1:
|
|
Operands[Operand] = Data.getU8(&Offset);
|
|
if (Signed)
|
|
Operands[Operand] = (int8_t)Operands[Operand];
|
|
break;
|
|
case Operation::Size2:
|
|
Operands[Operand] = Data.getU16(&Offset);
|
|
if (Signed)
|
|
Operands[Operand] = (int16_t)Operands[Operand];
|
|
break;
|
|
case Operation::Size4:
|
|
Operands[Operand] = Data.getU32(&Offset);
|
|
if (Signed)
|
|
Operands[Operand] = (int32_t)Operands[Operand];
|
|
break;
|
|
case Operation::Size8:
|
|
Operands[Operand] = Data.getU64(&Offset);
|
|
break;
|
|
case Operation::SizeAddr:
|
|
Operands[Operand] = Data.getUnsigned(&Offset, AddressSize);
|
|
break;
|
|
case Operation::SizeRefAddr:
|
|
if (!Format)
|
|
return false;
|
|
Operands[Operand] =
|
|
Data.getUnsigned(&Offset, dwarf::getDwarfOffsetByteSize(*Format));
|
|
break;
|
|
case Operation::SizeLEB:
|
|
if (Signed)
|
|
Operands[Operand] = Data.getSLEB128(&Offset);
|
|
else
|
|
Operands[Operand] = Data.getULEB128(&Offset);
|
|
break;
|
|
case Operation::BaseTypeRef:
|
|
Operands[Operand] = Data.getULEB128(&Offset);
|
|
break;
|
|
case Operation::WasmLocationArg:
|
|
assert(Operand == 1);
|
|
switch (Operands[0]) {
|
|
case 0:
|
|
case 1:
|
|
case 2:
|
|
case 4:
|
|
Operands[Operand] = Data.getULEB128(&Offset);
|
|
break;
|
|
case 3: // global as uint32
|
|
Operands[Operand] = Data.getU32(&Offset);
|
|
break;
|
|
default:
|
|
return false; // Unknown Wasm location
|
|
}
|
|
break;
|
|
case Operation::SizeBlock:
|
|
// We need a size, so this cannot be the first operand
|
|
if (Operand == 0)
|
|
return false;
|
|
// Store the offset of the block as the value.
|
|
Operands[Operand] = Offset;
|
|
Offset += Operands[Operand - 1];
|
|
break;
|
|
default:
|
|
llvm_unreachable("Unknown DWARFExpression Op size");
|
|
}
|
|
|
|
OperandEndOffsets[Operand] = Offset;
|
|
}
|
|
|
|
EndOffset = Offset;
|
|
return true;
|
|
}
|
|
|
|
std::optional<unsigned> DWARFExpression::Operation::getSubCode() const {
|
|
if (!Desc.Op.size() || Desc.Op[0] != Operation::SizeSubOpLEB)
|
|
return std::nullopt;
|
|
return Operands[0];
|
|
}
|
|
|
|
bool DWARFExpression::operator==(const DWARFExpression &RHS) const {
|
|
if (AddressSize != RHS.AddressSize || Format != RHS.Format)
|
|
return false;
|
|
return Data.getData() == RHS.Data.getData();
|
|
}
|
|
|
|
} // namespace llvm
|