aboutsummaryrefslogtreecommitdiff
path: root/vendor/gimli/src/write/op.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gimli/src/write/op.rs')
-rw-r--r--vendor/gimli/src/write/op.rs1618
1 files changed, 0 insertions, 1618 deletions
diff --git a/vendor/gimli/src/write/op.rs b/vendor/gimli/src/write/op.rs
deleted file mode 100644
index 287083b..0000000
--- a/vendor/gimli/src/write/op.rs
+++ /dev/null
@@ -1,1618 +0,0 @@
-use alloc::boxed::Box;
-use alloc::vec::Vec;
-
-use crate::common::{Encoding, Register};
-use crate::constants::{self, DwOp};
-use crate::leb128::write::{sleb128_size, uleb128_size};
-use crate::write::{
- Address, DebugInfoReference, Error, Reference, Result, UnitEntryId, UnitOffsets, Writer,
-};
-
-/// The bytecode for a DWARF expression or location description.
-#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
-pub struct Expression {
- operations: Vec<Operation>,
-}
-
-impl Expression {
- /// Create an empty expression.
- #[inline]
- pub fn new() -> Self {
- Self::default()
- }
-
- /// Create an expression from raw bytecode.
- ///
- /// This does not support operations that require references, such as `DW_OP_addr`.
- #[inline]
- pub fn raw(bytecode: Vec<u8>) -> Self {
- Expression {
- operations: vec![Operation::Raw(bytecode)],
- }
- }
-
- /// Add an operation to the expression.
- ///
- /// This should only be used for operations that have no explicit operands.
- pub fn op(&mut self, opcode: DwOp) {
- self.operations.push(Operation::Simple(opcode));
- }
-
- /// Add a `DW_OP_addr` operation to the expression.
- pub fn op_addr(&mut self, address: Address) {
- self.operations.push(Operation::Address(address));
- }
-
- /// Add a `DW_OP_constu` operation to the expression.
- ///
- /// This may be emitted as a smaller equivalent operation.
- pub fn op_constu(&mut self, value: u64) {
- self.operations.push(Operation::UnsignedConstant(value));
- }
-
- /// Add a `DW_OP_consts` operation to the expression.
- ///
- /// This may be emitted as a smaller equivalent operation.
- pub fn op_consts(&mut self, value: i64) {
- self.operations.push(Operation::SignedConstant(value));
- }
-
- /// Add a `DW_OP_const_type` or `DW_OP_GNU_const_type` operation to the expression.
- pub fn op_const_type(&mut self, base: UnitEntryId, value: Box<[u8]>) {
- self.operations.push(Operation::ConstantType(base, value));
- }
-
- /// Add a `DW_OP_fbreg` operation to the expression.
- pub fn op_fbreg(&mut self, offset: i64) {
- self.operations.push(Operation::FrameOffset(offset));
- }
-
- /// Add a `DW_OP_bregx` operation to the expression.
- ///
- /// This may be emitted as a smaller equivalent operation.
- pub fn op_breg(&mut self, register: Register, offset: i64) {
- self.operations
- .push(Operation::RegisterOffset(register, offset));
- }
-
- /// Add a `DW_OP_regval_type` or `DW_OP_GNU_regval_type` operation to the expression.
- ///
- /// This may be emitted as a smaller equivalent operation.
- pub fn op_regval_type(&mut self, register: Register, base: UnitEntryId) {
- self.operations
- .push(Operation::RegisterType(register, base));
- }
-
- /// Add a `DW_OP_pick` operation to the expression.
- ///
- /// This may be emitted as a `DW_OP_dup` or `DW_OP_over` operation.
- pub fn op_pick(&mut self, index: u8) {
- self.operations.push(Operation::Pick(index));
- }
-
- /// Add a `DW_OP_deref` operation to the expression.
- pub fn op_deref(&mut self) {
- self.operations.push(Operation::Deref { space: false });
- }
-
- /// Add a `DW_OP_xderef` operation to the expression.
- pub fn op_xderef(&mut self) {
- self.operations.push(Operation::Deref { space: true });
- }
-
- /// Add a `DW_OP_deref_size` operation to the expression.
- pub fn op_deref_size(&mut self, size: u8) {
- self.operations
- .push(Operation::DerefSize { size, space: false });
- }
-
- /// Add a `DW_OP_xderef_size` operation to the expression.
- pub fn op_xderef_size(&mut self, size: u8) {
- self.operations
- .push(Operation::DerefSize { size, space: true });
- }
-
- /// Add a `DW_OP_deref_type` or `DW_OP_GNU_deref_type` operation to the expression.
- pub fn op_deref_type(&mut self, size: u8, base: UnitEntryId) {
- self.operations.push(Operation::DerefType {
- size,
- base,
- space: false,
- });
- }
-
- /// Add a `DW_OP_xderef_type` operation to the expression.
- pub fn op_xderef_type(&mut self, size: u8, base: UnitEntryId) {
- self.operations.push(Operation::DerefType {
- size,
- base,
- space: true,
- });
- }
-
- /// Add a `DW_OP_plus_uconst` operation to the expression.
- pub fn op_plus_uconst(&mut self, value: u64) {
- self.operations.push(Operation::PlusConstant(value));
- }
-
- /// Add a `DW_OP_skip` operation to the expression.
- ///
- /// Returns the index of the operation. The caller must call `set_target` with
- /// this index to set the target of the branch.
- pub fn op_skip(&mut self) -> usize {
- let index = self.next_index();
- self.operations.push(Operation::Skip(!0));
- index
- }
-
- /// Add a `DW_OP_bra` operation to the expression.
- ///
- /// Returns the index of the operation. The caller must call `set_target` with
- /// this index to set the target of the branch.
- pub fn op_bra(&mut self) -> usize {
- let index = self.next_index();
- self.operations.push(Operation::Branch(!0));
- index
- }
-
- /// Return the index that will be assigned to the next operation.
- ///
- /// This can be passed to `set_target`.
- #[inline]
- pub fn next_index(&self) -> usize {
- self.operations.len()
- }
-
- /// Set the target of a `DW_OP_skip` or `DW_OP_bra` operation .
- pub fn set_target(&mut self, operation: usize, new_target: usize) {
- debug_assert!(new_target <= self.next_index());
- debug_assert_ne!(operation, new_target);
- match self.operations[operation] {
- Operation::Skip(ref mut target) | Operation::Branch(ref mut target) => {
- *target = new_target;
- }
- _ => unimplemented!(),
- }
- }
-
- /// Add a `DW_OP_call4` operation to the expression.
- pub fn op_call(&mut self, entry: UnitEntryId) {
- self.operations.push(Operation::Call(entry));
- }
-
- /// Add a `DW_OP_call_ref` operation to the expression.
- pub fn op_call_ref(&mut self, entry: Reference) {
- self.operations.push(Operation::CallRef(entry));
- }
-
- /// Add a `DW_OP_convert` or `DW_OP_GNU_convert` operation to the expression.
- ///
- /// `base` is the DIE of the base type, or `None` for the generic type.
- pub fn op_convert(&mut self, base: Option<UnitEntryId>) {
- self.operations.push(Operation::Convert(base));
- }
-
- /// Add a `DW_OP_reinterpret` or `DW_OP_GNU_reinterpret` operation to the expression.
- ///
- /// `base` is the DIE of the base type, or `None` for the generic type.
- pub fn op_reinterpret(&mut self, base: Option<UnitEntryId>) {
- self.operations.push(Operation::Reinterpret(base));
- }
-
- /// Add a `DW_OP_entry_value` or `DW_OP_GNU_entry_value` operation to the expression.
- pub fn op_entry_value(&mut self, expression: Expression) {
- self.operations.push(Operation::EntryValue(expression));
- }
-
- /// Add a `DW_OP_regx` operation to the expression.
- ///
- /// This may be emitted as a smaller equivalent operation.
- pub fn op_reg(&mut self, register: Register) {
- self.operations.push(Operation::Register(register));
- }
-
- /// Add a `DW_OP_implicit_value` operation to the expression.
- pub fn op_implicit_value(&mut self, data: Box<[u8]>) {
- self.operations.push(Operation::ImplicitValue(data));
- }
-
- /// Add a `DW_OP_implicit_pointer` or `DW_OP_GNU_implicit_pointer` operation to the expression.
- pub fn op_implicit_pointer(&mut self, entry: Reference, byte_offset: i64) {
- self.operations
- .push(Operation::ImplicitPointer { entry, byte_offset });
- }
-
- /// Add a `DW_OP_piece` operation to the expression.
- pub fn op_piece(&mut self, size_in_bytes: u64) {
- self.operations.push(Operation::Piece { size_in_bytes });
- }
-
- /// Add a `DW_OP_bit_piece` operation to the expression.
- pub fn op_bit_piece(&mut self, size_in_bits: u64, bit_offset: u64) {
- self.operations.push(Operation::BitPiece {
- size_in_bits,
- bit_offset,
- });
- }
-
- /// Add a `DW_OP_GNU_parameter_ref` operation to the expression.
- pub fn op_gnu_parameter_ref(&mut self, entry: UnitEntryId) {
- self.operations.push(Operation::ParameterRef(entry));
- }
-
- /// Add a `DW_OP_WASM_location 0x0` operation to the expression.
- pub fn op_wasm_local(&mut self, index: u32) {
- self.operations.push(Operation::WasmLocal(index));
- }
-
- /// Add a `DW_OP_WASM_location 0x1` operation to the expression.
- pub fn op_wasm_global(&mut self, index: u32) {
- self.operations.push(Operation::WasmGlobal(index));
- }
-
- /// Add a `DW_OP_WASM_location 0x2` operation to the expression.
- pub fn op_wasm_stack(&mut self, index: u32) {
- self.operations.push(Operation::WasmStack(index));
- }
-
- pub(crate) fn size(&self, encoding: Encoding, unit_offsets: Option<&UnitOffsets>) -> usize {
- let mut size = 0;
- for operation in &self.operations {
- size += operation.size(encoding, unit_offsets);
- }
- size
- }
-
- pub(crate) fn write<W: Writer>(
- &self,
- w: &mut W,
- mut refs: Option<&mut Vec<DebugInfoReference>>,
- encoding: Encoding,
- unit_offsets: Option<&UnitOffsets>,
- ) -> Result<()> {
- // TODO: only calculate offsets if needed?
- let mut offsets = Vec::with_capacity(self.operations.len());
- let mut offset = w.len();
- for operation in &self.operations {
- offsets.push(offset);
- offset += operation.size(encoding, unit_offsets);
- }
- offsets.push(offset);
- for (operation, offset) in self.operations.iter().zip(offsets.iter().copied()) {
- debug_assert_eq!(w.len(), offset);
- operation.write(w, refs.as_deref_mut(), encoding, unit_offsets, &offsets)?;
- }
- Ok(())
- }
-}
-
-/// A single DWARF operation.
-//
-// This type is intentionally not public so that we can change the
-// representation of expressions as needed.
-//
-// Variants are listed in the order they appear in Section 2.5.
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-enum Operation {
- /// Raw bytecode.
- ///
- /// Does not support references.
- Raw(Vec<u8>),
- /// An operation that has no explicit operands.
- ///
- /// Represents:
- /// - `DW_OP_drop`, `DW_OP_swap`, `DW_OP_rot`
- /// - `DW_OP_push_object_address`, `DW_OP_form_tls_address`, `DW_OP_call_frame_cfa`
- /// - `DW_OP_abs`, `DW_OP_and`, `DW_OP_div`, `DW_OP_minus`, `DW_OP_mod`, `DW_OP_mul`,
- /// `DW_OP_neg`, `DW_OP_not`, `DW_OP_or`, `DW_OP_plus`, `DW_OP_shl`, `DW_OP_shr`,
- /// `DW_OP_shra`, `DW_OP_xor`
- /// - `DW_OP_le`, `DW_OP_ge`, `DW_OP_eq`, `DW_OP_lt`, `DW_OP_gt`, `DW_OP_ne`
- /// - `DW_OP_nop`
- /// - `DW_OP_stack_value`
- Simple(DwOp),
- /// Relocate the address if needed, and push it on the stack.
- ///
- /// Represents `DW_OP_addr`.
- Address(Address),
- /// Push an unsigned constant value on the stack.
- ///
- /// Represents `DW_OP_constu`.
- UnsignedConstant(u64),
- /// Push a signed constant value on the stack.
- ///
- /// Represents `DW_OP_consts`.
- SignedConstant(i64),
- /* TODO: requires .debug_addr write support
- /// Read the address at the given index in `.debug_addr, relocate the address if needed,
- /// and push it on the stack.
- ///
- /// Represents `DW_OP_addrx`.
- AddressIndex(DebugAddrIndex<Offset>),
- /// Read the address at the given index in `.debug_addr, and push it on the stack.
- /// Do not relocate the address.
- ///
- /// Represents `DW_OP_constx`.
- ConstantIndex(DebugAddrIndex<Offset>),
- */
- /// Interpret the value bytes as a constant of a given type, and push it on the stack.
- ///
- /// Represents `DW_OP_const_type`.
- ConstantType(UnitEntryId, Box<[u8]>),
- /// Compute the frame base (using `DW_AT_frame_base`), add the
- /// given offset, and then push the resulting sum on the stack.
- ///
- /// Represents `DW_OP_fbreg`.
- FrameOffset(i64),
- /// Find the contents of the given register, add the offset, and then
- /// push the resulting sum on the stack.
- ///
- /// Represents `DW_OP_bregx`.
- RegisterOffset(Register, i64),
- /// Interpret the contents of the given register as a value of the given type,
- /// and push it on the stack.
- ///
- /// Represents `DW_OP_regval_type`.
- RegisterType(Register, UnitEntryId),
- /// Copy the item at a stack index and push it on top of the stack.
- ///
- /// Represents `DW_OP_pick`, `DW_OP_dup`, and `DW_OP_over`.
- Pick(u8),
- /// Pop the topmost value of the stack, dereference it, and push the
- /// resulting value.
- ///
- /// Represents `DW_OP_deref` and `DW_OP_xderef`.
- Deref {
- /// True if the dereference operation takes an address space
- /// argument from the stack; false otherwise.
- space: bool,
- },
- /// Pop the topmost value of the stack, dereference it to obtain a value
- /// of the given size, and push the resulting value.
- ///
- /// Represents `DW_OP_deref_size` and `DW_OP_xderef_size`.
- DerefSize {
- /// True if the dereference operation takes an address space
- /// argument from the stack; false otherwise.
- space: bool,
- /// The size of the data to dereference.
- size: u8,
- },
- /// Pop the topmost value of the stack, dereference it to obtain a value
- /// of the given type, and push the resulting value.
- ///
- /// Represents `DW_OP_deref_type` and `DW_OP_xderef_type`.
- DerefType {
- /// True if the dereference operation takes an address space
- /// argument from the stack; false otherwise.
- space: bool,
- /// The size of the data to dereference.
- size: u8,
- /// The DIE of the base type, or `None` for the generic type.
- base: UnitEntryId,
- },
- /// Add an unsigned constant to the topmost value on the stack.
- ///
- /// Represents `DW_OP_plus_uconst`.
- PlusConstant(u64),
- /// Unconditional branch to the target location.
- ///
- /// The value is the index within the expression of the operation to branch to.
- /// This will be converted to a relative offset when writing.
- ///
- /// Represents `DW_OP_skip`.
- Skip(usize),
- /// Branch to the target location if the top of stack is nonzero.
- ///
- /// The value is the index within the expression of the operation to branch to.
- /// This will be converted to a relative offset when writing.
- ///
- /// Represents `DW_OP_bra`.
- Branch(usize),
- /// Evaluate a DWARF expression as a subroutine.
- ///
- /// The expression comes from the `DW_AT_location` attribute of the indicated DIE.
- ///
- /// Represents `DW_OP_call4`.
- Call(UnitEntryId),
- /// Evaluate an external DWARF expression as a subroutine.
- ///
- /// The expression comes from the `DW_AT_location` attribute of the indicated DIE,
- /// which may be in another compilation unit or shared object.
- ///
- /// Represents `DW_OP_call_ref`.
- CallRef(Reference),
- /// Pop the top stack entry, convert it to a different type, and push it on the stack.
- ///
- /// Represents `DW_OP_convert`.
- Convert(Option<UnitEntryId>),
- /// Pop the top stack entry, reinterpret the bits in its value as a different type,
- /// and push it on the stack.
- ///
- /// Represents `DW_OP_reinterpret`.
- Reinterpret(Option<UnitEntryId>),
- /// Evaluate an expression at the entry to the current subprogram, and push it on the stack.
- ///
- /// Represents `DW_OP_entry_value`.
- EntryValue(Expression),
- // FIXME: EntryRegister
- /// Indicate that this piece's location is in the given register.
- ///
- /// Completes the piece or expression.
- ///
- /// Represents `DW_OP_regx`.
- Register(Register),
- /// The object has no location, but has a known constant value.
- ///
- /// Completes the piece or expression.
- ///
- /// Represents `DW_OP_implicit_value`.
- ImplicitValue(Box<[u8]>),
- /// The object is a pointer to a value which has no actual location, such as
- /// an implicit value or a stack value.
- ///
- /// Completes the piece or expression.
- ///
- /// Represents `DW_OP_implicit_pointer`.
- ImplicitPointer {
- /// The DIE of the value that this is an implicit pointer into.
- entry: Reference,
- /// The byte offset into the value that the implicit pointer points to.
- byte_offset: i64,
- },
- /// Terminate a piece.
- ///
- /// Represents `DW_OP_piece`.
- Piece {
- /// The size of this piece in bytes.
- size_in_bytes: u64,
- },
- /// Terminate a piece with a size in bits.
- ///
- /// Represents `DW_OP_bit_piece`.
- BitPiece {
- /// The size of this piece in bits.
- size_in_bits: u64,
- /// The bit offset of this piece.
- bit_offset: u64,
- },
- /// This represents a parameter that was optimized out.
- ///
- /// The entry is the definition of the parameter, and is matched to
- /// the `DW_TAG_GNU_call_site_parameter` in the caller that also
- /// points to the same definition of the parameter.
- ///
- /// Represents `DW_OP_GNU_parameter_ref`.
- ParameterRef(UnitEntryId),
- /// The index of a local in the currently executing function.
- ///
- /// Represents `DW_OP_WASM_location 0x00`.
- WasmLocal(u32),
- /// The index of a global.
- ///
- /// Represents `DW_OP_WASM_location 0x01`.
- WasmGlobal(u32),
- /// The index of an item on the operand stack.
- ///
- /// Represents `DW_OP_WASM_location 0x02`.
- WasmStack(u32),
-}
-
-impl Operation {
- fn size(&self, encoding: Encoding, unit_offsets: Option<&UnitOffsets>) -> usize {
- let base_size = |base| {
- // Errors are handled during writes.
- match unit_offsets {
- Some(offsets) => uleb128_size(offsets.unit_offset(base)),
- None => 0,
- }
- };
- 1 + match *self {
- Operation::Raw(ref bytecode) => return bytecode.len(),
- Operation::Simple(_) => 0,
- Operation::Address(_) => encoding.address_size as usize,
- Operation::UnsignedConstant(value) => {
- if value < 32 {
- 0
- } else {
- uleb128_size(value)
- }
- }
- Operation::SignedConstant(value) => sleb128_size(value),
- Operation::ConstantType(base, ref value) => base_size(base) + 1 + value.len(),
- Operation::FrameOffset(offset) => sleb128_size(offset),
- Operation::RegisterOffset(register, offset) => {
- if register.0 < 32 {
- sleb128_size(offset)
- } else {
- uleb128_size(register.0.into()) + sleb128_size(offset)
- }
- }
- Operation::RegisterType(register, base) => {
- uleb128_size(register.0.into()) + base_size(base)
- }
- Operation::Pick(index) => {
- if index > 1 {
- 1
- } else {
- 0
- }
- }
- Operation::Deref { .. } => 0,
- Operation::DerefSize { .. } => 1,
- Operation::DerefType { base, .. } => 1 + base_size(base),
- Operation::PlusConstant(value) => uleb128_size(value),
- Operation::Skip(_) => 2,
- Operation::Branch(_) => 2,
- Operation::Call(_) => 4,
- Operation::CallRef(_) => encoding.format.word_size() as usize,
- Operation::Convert(base) => match base {
- Some(base) => base_size(base),
- None => 1,
- },
- Operation::Reinterpret(base) => match base {
- Some(base) => base_size(base),
- None => 1,
- },
- Operation::EntryValue(ref expression) => {
- let length = expression.size(encoding, unit_offsets);
- uleb128_size(length as u64) + length
- }
- Operation::Register(register) => {
- if register.0 < 32 {
- 0
- } else {
- uleb128_size(register.0.into())
- }
- }
- Operation::ImplicitValue(ref data) => uleb128_size(data.len() as u64) + data.len(),
- Operation::ImplicitPointer { byte_offset, .. } => {
- encoding.format.word_size() as usize + sleb128_size(byte_offset)
- }
- Operation::Piece { size_in_bytes } => uleb128_size(size_in_bytes),
- Operation::BitPiece {
- size_in_bits,
- bit_offset,
- } => uleb128_size(size_in_bits) + uleb128_size(bit_offset),
- Operation::ParameterRef(_) => 4,
- Operation::WasmLocal(index)
- | Operation::WasmGlobal(index)
- | Operation::WasmStack(index) => 1 + uleb128_size(index.into()),
- }
- }
-
- pub(crate) fn write<W: Writer>(
- &self,
- w: &mut W,
- refs: Option<&mut Vec<DebugInfoReference>>,
- encoding: Encoding,
- unit_offsets: Option<&UnitOffsets>,
- offsets: &[usize],
- ) -> Result<()> {
- let entry_offset = |entry| match unit_offsets {
- Some(offsets) => {
- let offset = offsets.unit_offset(entry);
- if offset == 0 {
- Err(Error::UnsupportedExpressionForwardReference)
- } else {
- Ok(offset)
- }
- }
- None => Err(Error::UnsupportedCfiExpressionReference),
- };
- match *self {
- Operation::Raw(ref bytecode) => w.write(bytecode)?,
- Operation::Simple(opcode) => w.write_u8(opcode.0)?,
- Operation::Address(address) => {
- w.write_u8(constants::DW_OP_addr.0)?;
- w.write_address(address, encoding.address_size)?;
- }
- Operation::UnsignedConstant(value) => {
- if value < 32 {
- w.write_u8(constants::DW_OP_lit0.0 + value as u8)?;
- } else {
- w.write_u8(constants::DW_OP_constu.0)?;
- w.write_uleb128(value)?;
- }
- }
- Operation::SignedConstant(value) => {
- w.write_u8(constants::DW_OP_consts.0)?;
- w.write_sleb128(value)?;
- }
- Operation::ConstantType(base, ref value) => {
- if encoding.version >= 5 {
- w.write_u8(constants::DW_OP_const_type.0)?;
- } else {
- w.write_u8(constants::DW_OP_GNU_const_type.0)?;
- }
- w.write_uleb128(entry_offset(base)?)?;
- w.write_udata(value.len() as u64, 1)?;
- w.write(value)?;
- }
- Operation::FrameOffset(offset) => {
- w.write_u8(constants::DW_OP_fbreg.0)?;
- w.write_sleb128(offset)?;
- }
- Operation::RegisterOffset(register, offset) => {
- if register.0 < 32 {
- w.write_u8(constants::DW_OP_breg0.0 + register.0 as u8)?;
- } else {
- w.write_u8(constants::DW_OP_bregx.0)?;
- w.write_uleb128(register.0.into())?;
- }
- w.write_sleb128(offset)?;
- }
- Operation::RegisterType(register, base) => {
- if encoding.version >= 5 {
- w.write_u8(constants::DW_OP_regval_type.0)?;
- } else {
- w.write_u8(constants::DW_OP_GNU_regval_type.0)?;
- }
- w.write_uleb128(register.0.into())?;
- w.write_uleb128(entry_offset(base)?)?;
- }
- Operation::Pick(index) => match index {
- 0 => w.write_u8(constants::DW_OP_dup.0)?,
- 1 => w.write_u8(constants::DW_OP_over.0)?,
- _ => {
- w.write_u8(constants::DW_OP_pick.0)?;
- w.write_u8(index)?;
- }
- },
- Operation::Deref { space } => {
- if space {
- w.write_u8(constants::DW_OP_xderef.0)?;
- } else {
- w.write_u8(constants::DW_OP_deref.0)?;
- }
- }
- Operation::DerefSize { space, size } => {
- if space {
- w.write_u8(constants::DW_OP_xderef_size.0)?;
- } else {
- w.write_u8(constants::DW_OP_deref_size.0)?;
- }
- w.write_u8(size)?;
- }
- Operation::DerefType { space, size, base } => {
- if space {
- w.write_u8(constants::DW_OP_xderef_type.0)?;
- } else {
- if encoding.version >= 5 {
- w.write_u8(constants::DW_OP_deref_type.0)?;
- } else {
- w.write_u8(constants::DW_OP_GNU_deref_type.0)?;
- }
- }
- w.write_u8(size)?;
- w.write_uleb128(entry_offset(base)?)?;
- }
- Operation::PlusConstant(value) => {
- w.write_u8(constants::DW_OP_plus_uconst.0)?;
- w.write_uleb128(value)?;
- }
- Operation::Skip(target) => {
- w.write_u8(constants::DW_OP_skip.0)?;
- let offset = offsets[target] as i64 - (w.len() as i64 + 2);
- w.write_sdata(offset, 2)?;
- }
- Operation::Branch(target) => {
- w.write_u8(constants::DW_OP_bra.0)?;
- let offset = offsets[target] as i64 - (w.len() as i64 + 2);
- w.write_sdata(offset, 2)?;
- }
- Operation::Call(entry) => {
- w.write_u8(constants::DW_OP_call4.0)?;
- // TODO: this probably won't work in practice, because we may
- // only know the offsets of base type DIEs at this point.
- w.write_udata(entry_offset(entry)?, 4)?;
- }
- Operation::CallRef(entry) => {
- w.write_u8(constants::DW_OP_call_ref.0)?;
- let size = encoding.format.word_size();
- match entry {
- Reference::Symbol(symbol) => w.write_reference(symbol, size)?,
- Reference::Entry(unit, entry) => {
- let refs = refs.ok_or(Error::InvalidReference)?;
- refs.push(DebugInfoReference {
- offset: w.len(),
- unit,
- entry,
- size,
- });
- w.write_udata(0, size)?;
- }
- }
- }
- Operation::Convert(base) => {
- if encoding.version >= 5 {
- w.write_u8(constants::DW_OP_convert.0)?;
- } else {
- w.write_u8(constants::DW_OP_GNU_convert.0)?;
- }
- match base {
- Some(base) => w.write_uleb128(entry_offset(base)?)?,
- None => w.write_u8(0)?,
- }
- }
- Operation::Reinterpret(base) => {
- if encoding.version >= 5 {
- w.write_u8(constants::DW_OP_reinterpret.0)?;
- } else {
- w.write_u8(constants::DW_OP_GNU_reinterpret.0)?;
- }
- match base {
- Some(base) => w.write_uleb128(entry_offset(base)?)?,
- None => w.write_u8(0)?,
- }
- }
- Operation::EntryValue(ref expression) => {
- if encoding.version >= 5 {
- w.write_u8(constants::DW_OP_entry_value.0)?;
- } else {
- w.write_u8(constants::DW_OP_GNU_entry_value.0)?;
- }
- let length = expression.size(encoding, unit_offsets);
- w.write_uleb128(length as u64)?;
- expression.write(w, refs, encoding, unit_offsets)?;
- }
- Operation::Register(register) => {
- if register.0 < 32 {
- w.write_u8(constants::DW_OP_reg0.0 + register.0 as u8)?;
- } else {
- w.write_u8(constants::DW_OP_regx.0)?;
- w.write_uleb128(register.0.into())?;
- }
- }
- Operation::ImplicitValue(ref data) => {
- w.write_u8(constants::DW_OP_implicit_value.0)?;
- w.write_uleb128(data.len() as u64)?;
- w.write(data)?;
- }
- Operation::ImplicitPointer { entry, byte_offset } => {
- if encoding.version >= 5 {
- w.write_u8(constants::DW_OP_implicit_pointer.0)?;
- } else {
- w.write_u8(constants::DW_OP_GNU_implicit_pointer.0)?;
- }
- let size = if encoding.version == 2 {
- encoding.address_size
- } else {
- encoding.format.word_size()
- };
- match entry {
- Reference::Symbol(symbol) => {
- w.write_reference(symbol, size)?;
- }
- Reference::Entry(unit, entry) => {
- let refs = refs.ok_or(Error::InvalidReference)?;
- refs.push(DebugInfoReference {
- offset: w.len(),
- unit,
- entry,
- size,
- });
- w.write_udata(0, size)?;
- }
- }
- w.write_sleb128(byte_offset)?;
- }
- Operation::Piece { size_in_bytes } => {
- w.write_u8(constants::DW_OP_piece.0)?;
- w.write_uleb128(size_in_bytes)?;
- }
- Operation::BitPiece {
- size_in_bits,
- bit_offset,
- } => {
- w.write_u8(constants::DW_OP_bit_piece.0)?;
- w.write_uleb128(size_in_bits)?;
- w.write_uleb128(bit_offset)?;
- }
- Operation::ParameterRef(entry) => {
- w.write_u8(constants::DW_OP_GNU_parameter_ref.0)?;
- w.write_udata(entry_offset(entry)?, 4)?;
- }
- Operation::WasmLocal(index) => {
- w.write(&[constants::DW_OP_WASM_location.0, 0])?;
- w.write_uleb128(index.into())?;
- }
- Operation::WasmGlobal(index) => {
- w.write(&[constants::DW_OP_WASM_location.0, 1])?;
- w.write_uleb128(index.into())?;
- }
- Operation::WasmStack(index) => {
- w.write(&[constants::DW_OP_WASM_location.0, 2])?;
- w.write_uleb128(index.into())?;
- }
- }
- Ok(())
- }
-}
-
-#[cfg(feature = "read")]
-pub(crate) mod convert {
- use super::*;
- use crate::common::UnitSectionOffset;
- use crate::read::{self, Reader};
- use crate::write::{ConvertError, ConvertResult, UnitEntryId, UnitId};
- use std::collections::HashMap;
-
- impl Expression {
- /// Create an expression from the input expression.
- pub fn from<R: Reader<Offset = usize>>(
- from_expression: read::Expression<R>,
- encoding: Encoding,
- dwarf: Option<&read::Dwarf<R>>,
- unit: Option<&read::Unit<R>>,
- entry_ids: Option<&HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>>,
- convert_address: &dyn Fn(u64) -> Option<Address>,
- ) -> ConvertResult<Expression> {
- let convert_unit_offset = |offset: read::UnitOffset| -> ConvertResult<_> {
- let entry_ids = entry_ids.ok_or(ConvertError::UnsupportedOperation)?;
- let unit = unit.ok_or(ConvertError::UnsupportedOperation)?;
- let id = entry_ids
- .get(&offset.to_unit_section_offset(unit))
- .ok_or(ConvertError::InvalidUnitRef)?;
- Ok(id.1)
- };
- let convert_debug_info_offset = |offset| -> ConvertResult<_> {
- // TODO: support relocations
- let entry_ids = entry_ids.ok_or(ConvertError::UnsupportedOperation)?;
- let id = entry_ids
- .get(&UnitSectionOffset::DebugInfoOffset(offset))
- .ok_or(ConvertError::InvalidDebugInfoRef)?;
- Ok(Reference::Entry(id.0, id.1))
- };
-
- // Calculate offsets for use in branch/skip operations.
- let mut offsets = Vec::new();
- let mut offset = 0;
- let mut from_operations = from_expression.clone().operations(encoding);
- while from_operations.next()?.is_some() {
- offsets.push(offset);
- offset = from_operations.offset_from(&from_expression);
- }
- offsets.push(from_expression.0.len());
-
- let mut from_operations = from_expression.clone().operations(encoding);
- let mut operations = Vec::new();
- while let Some(from_operation) = from_operations.next()? {
- let operation = match from_operation {
- read::Operation::Deref {
- base_type,
- size,
- space,
- } => {
- if base_type.0 != 0 {
- let base = convert_unit_offset(base_type)?;
- Operation::DerefType { space, size, base }
- } else if size != encoding.address_size {
- Operation::DerefSize { space, size }
- } else {
- Operation::Deref { space }
- }
- }
- read::Operation::Drop => Operation::Simple(constants::DW_OP_drop),
- read::Operation::Pick { index } => Operation::Pick(index),
- read::Operation::Swap => Operation::Simple(constants::DW_OP_swap),
- read::Operation::Rot => Operation::Simple(constants::DW_OP_rot),
- read::Operation::Abs => Operation::Simple(constants::DW_OP_abs),
- read::Operation::And => Operation::Simple(constants::DW_OP_and),
- read::Operation::Div => Operation::Simple(constants::DW_OP_div),
- read::Operation::Minus => Operation::Simple(constants::DW_OP_minus),
- read::Operation::Mod => Operation::Simple(constants::DW_OP_mod),
- read::Operation::Mul => Operation::Simple(constants::DW_OP_mul),
- read::Operation::Neg => Operation::Simple(constants::DW_OP_neg),
- read::Operation::Not => Operation::Simple(constants::DW_OP_not),
- read::Operation::Or => Operation::Simple(constants::DW_OP_or),
- read::Operation::Plus => Operation::Simple(constants::DW_OP_plus),
- read::Operation::PlusConstant { value } => Operation::PlusConstant(value),
- read::Operation::Shl => Operation::Simple(constants::DW_OP_shl),
- read::Operation::Shr => Operation::Simple(constants::DW_OP_shr),
- read::Operation::Shra => Operation::Simple(constants::DW_OP_shra),
- read::Operation::Xor => Operation::Simple(constants::DW_OP_xor),
- read::Operation::Eq => Operation::Simple(constants::DW_OP_eq),
- read::Operation::Ge => Operation::Simple(constants::DW_OP_ge),
- read::Operation::Gt => Operation::Simple(constants::DW_OP_gt),
- read::Operation::Le => Operation::Simple(constants::DW_OP_le),
- read::Operation::Lt => Operation::Simple(constants::DW_OP_lt),
- read::Operation::Ne => Operation::Simple(constants::DW_OP_ne),
- read::Operation::Bra { target } => {
- let offset = from_operations
- .offset_from(&from_expression)
- .wrapping_add(i64::from(target) as usize);
- let index = offsets
- .binary_search(&offset)
- .map_err(|_| ConvertError::InvalidBranchTarget)?;
- Operation::Branch(index)
- }
- read::Operation::Skip { target } => {
- let offset = from_operations
- .offset_from(&from_expression)
- .wrapping_add(i64::from(target) as usize);
- let index = offsets
- .binary_search(&offset)
- .map_err(|_| ConvertError::InvalidBranchTarget)?;
- Operation::Skip(index)
- }
- read::Operation::UnsignedConstant { value } => {
- Operation::UnsignedConstant(value)
- }
- read::Operation::SignedConstant { value } => Operation::SignedConstant(value),
- read::Operation::Register { register } => Operation::Register(register),
- read::Operation::RegisterOffset {
- register,
- offset,
- base_type,
- } => {
- if base_type.0 != 0 {
- Operation::RegisterType(register, convert_unit_offset(base_type)?)
- } else {
- Operation::RegisterOffset(register, offset)
- }
- }
- read::Operation::FrameOffset { offset } => Operation::FrameOffset(offset),
- read::Operation::Nop => Operation::Simple(constants::DW_OP_nop),
- read::Operation::PushObjectAddress => {
- Operation::Simple(constants::DW_OP_push_object_address)
- }
- read::Operation::Call { offset } => match offset {
- read::DieReference::UnitRef(offset) => {
- Operation::Call(convert_unit_offset(offset)?)
- }
- read::DieReference::DebugInfoRef(offset) => {
- Operation::CallRef(convert_debug_info_offset(offset)?)
- }
- },
- read::Operation::TLS => Operation::Simple(constants::DW_OP_form_tls_address),
- read::Operation::CallFrameCFA => {
- Operation::Simple(constants::DW_OP_call_frame_cfa)
- }
- read::Operation::Piece {
- size_in_bits,
- bit_offset: None,
- } => Operation::Piece {
- size_in_bytes: size_in_bits / 8,
- },
- read::Operation::Piece {
- size_in_bits,
- bit_offset: Some(bit_offset),
- } => Operation::BitPiece {
- size_in_bits,
- bit_offset,
- },
- read::Operation::ImplicitValue { data } => {
- Operation::ImplicitValue(data.to_slice()?.into_owned().into())
- }
- read::Operation::StackValue => Operation::Simple(constants::DW_OP_stack_value),
- read::Operation::ImplicitPointer { value, byte_offset } => {
- let entry = convert_debug_info_offset(value)?;
- Operation::ImplicitPointer { entry, byte_offset }
- }
- read::Operation::EntryValue { expression } => {
- let expression = Expression::from(
- read::Expression(expression),
- encoding,
- dwarf,
- unit,
- entry_ids,
- convert_address,
- )?;
- Operation::EntryValue(expression)
- }
- read::Operation::ParameterRef { offset } => {
- let entry = convert_unit_offset(offset)?;
- Operation::ParameterRef(entry)
- }
- read::Operation::Address { address } => {
- let address =
- convert_address(address).ok_or(ConvertError::InvalidAddress)?;
- Operation::Address(address)
- }
- read::Operation::AddressIndex { index } => {
- let dwarf = dwarf.ok_or(ConvertError::UnsupportedOperation)?;
- let unit = unit.ok_or(ConvertError::UnsupportedOperation)?;
- let val = dwarf.address(unit, index)?;
- let address = convert_address(val).ok_or(ConvertError::InvalidAddress)?;
- Operation::Address(address)
- }
- read::Operation::ConstantIndex { index } => {
- let dwarf = dwarf.ok_or(ConvertError::UnsupportedOperation)?;
- let unit = unit.ok_or(ConvertError::UnsupportedOperation)?;
- let val = dwarf.address(unit, index)?;
- Operation::UnsignedConstant(val)
- }
- read::Operation::TypedLiteral { base_type, value } => {
- let entry = convert_unit_offset(base_type)?;
- Operation::ConstantType(entry, value.to_slice()?.into_owned().into())
- }
- read::Operation::Convert { base_type } => {
- if base_type.0 == 0 {
- Operation::Convert(None)
- } else {
- let entry = convert_unit_offset(base_type)?;
- Operation::Convert(Some(entry))
- }
- }
- read::Operation::Reinterpret { base_type } => {
- if base_type.0 == 0 {
- Operation::Reinterpret(None)
- } else {
- let entry = convert_unit_offset(base_type)?;
- Operation::Reinterpret(Some(entry))
- }
- }
- read::Operation::WasmLocal { index } => Operation::WasmLocal(index),
- read::Operation::WasmGlobal { index } => Operation::WasmGlobal(index),
- read::Operation::WasmStack { index } => Operation::WasmStack(index),
- };
- operations.push(operation);
- }
- Ok(Expression { operations })
- }
- }
-}
-
-#[cfg(test)]
-#[cfg(feature = "read")]
-mod tests {
- use super::*;
- use crate::common::{
- DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLocListsBase, DebugRngListsBase,
- DebugStrOffsetsBase, Format, SectionId,
- };
- use crate::read;
- use crate::write::{
- DebugLineStrOffsets, DebugStrOffsets, EndianVec, LineProgram, Sections, Unit, UnitTable,
- };
- use crate::LittleEndian;
- use std::collections::HashMap;
- use std::sync::Arc;
-
- #[test]
- fn test_operation() {
- for &version in &[3, 4, 5] {
- for &address_size in &[4, 8] {
- for &format in &[Format::Dwarf32, Format::Dwarf64] {
- let encoding = Encoding {
- format,
- version,
- address_size,
- };
-
- let mut units = UnitTable::default();
- let unit_id = units.add(Unit::new(encoding, LineProgram::none()));
- let unit = units.get_mut(unit_id);
- let entry_id = unit.add(unit.root(), constants::DW_TAG_base_type);
- let reference = Reference::Entry(unit_id, entry_id);
-
- let mut sections = Sections::new(EndianVec::new(LittleEndian));
- let debug_line_str_offsets = DebugLineStrOffsets::none();
- let debug_str_offsets = DebugStrOffsets::none();
- let debug_info_offsets = units
- .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets)
- .unwrap();
- let unit_offsets = debug_info_offsets.unit_offsets(unit_id);
- let debug_info_offset = unit_offsets.debug_info_offset(entry_id);
- let entry_offset =
- read::UnitOffset(unit_offsets.unit_offset(entry_id) as usize);
-
- let mut reg_expression = Expression::new();
- reg_expression.op_reg(Register(23));
-
- let operations: &[(&dyn Fn(&mut Expression), Operation, read::Operation<_>)] =
- &[
- (
- &|x| x.op_deref(),
- Operation::Deref { space: false },
- read::Operation::Deref {
- base_type: read::UnitOffset(0),
- size: address_size,
- space: false,
- },
- ),
- (
- &|x| x.op_xderef(),
- Operation::Deref { space: true },
- read::Operation::Deref {
- base_type: read::UnitOffset(0),
- size: address_size,
- space: true,
- },
- ),
- (
- &|x| x.op_deref_size(2),
- Operation::DerefSize {
- space: false,
- size: 2,
- },
- read::Operation::Deref {
- base_type: read::UnitOffset(0),
- size: 2,
- space: false,
- },
- ),
- (
- &|x| x.op_xderef_size(2),
- Operation::DerefSize {
- space: true,
- size: 2,
- },
- read::Operation::Deref {
- base_type: read::UnitOffset(0),
- size: 2,
- space: true,
- },
- ),
- (
- &|x| x.op_deref_type(2, entry_id),
- Operation::DerefType {
- space: false,
- size: 2,
- base: entry_id,
- },
- read::Operation::Deref {
- base_type: entry_offset,
- size: 2,
- space: false,
- },
- ),
- (
- &|x| x.op_xderef_type(2, entry_id),
- Operation::DerefType {
- space: true,
- size: 2,
- base: entry_id,
- },
- read::Operation::Deref {
- base_type: entry_offset,
- size: 2,
- space: true,
- },
- ),
- (
- &|x| x.op(constants::DW_OP_drop),
- Operation::Simple(constants::DW_OP_drop),
- read::Operation::Drop,
- ),
- (
- &|x| x.op_pick(0),
- Operation::Pick(0),
- read::Operation::Pick { index: 0 },
- ),
- (
- &|x| x.op_pick(1),
- Operation::Pick(1),
- read::Operation::Pick { index: 1 },
- ),
- (
- &|x| x.op_pick(2),
- Operation::Pick(2),
- read::Operation::Pick { index: 2 },
- ),
- (
- &|x| x.op(constants::DW_OP_swap),
- Operation::Simple(constants::DW_OP_swap),
- read::Operation::Swap,
- ),
- (
- &|x| x.op(constants::DW_OP_rot),
- Operation::Simple(constants::DW_OP_rot),
- read::Operation::Rot,
- ),
- (
- &|x| x.op(constants::DW_OP_abs),
- Operation::Simple(constants::DW_OP_abs),
- read::Operation::Abs,
- ),
- (
- &|x| x.op(constants::DW_OP_and),
- Operation::Simple(constants::DW_OP_and),
- read::Operation::And,
- ),
- (
- &|x| x.op(constants::DW_OP_div),
- Operation::Simple(constants::DW_OP_div),
- read::Operation::Div,
- ),
- (
- &|x| x.op(constants::DW_OP_minus),
- Operation::Simple(constants::DW_OP_minus),
- read::Operation::Minus,
- ),
- (
- &|x| x.op(constants::DW_OP_mod),
- Operation::Simple(constants::DW_OP_mod),
- read::Operation::Mod,
- ),
- (
- &|x| x.op(constants::DW_OP_mul),
- Operation::Simple(constants::DW_OP_mul),
- read::Operation::Mul,
- ),
- (
- &|x| x.op(constants::DW_OP_neg),
- Operation::Simple(constants::DW_OP_neg),
- read::Operation::Neg,
- ),
- (
- &|x| x.op(constants::DW_OP_not),
- Operation::Simple(constants::DW_OP_not),
- read::Operation::Not,
- ),
- (
- &|x| x.op(constants::DW_OP_or),
- Operation::Simple(constants::DW_OP_or),
- read::Operation::Or,
- ),
- (
- &|x| x.op(constants::DW_OP_plus),
- Operation::Simple(constants::DW_OP_plus),
- read::Operation::Plus,
- ),
- (
- &|x| x.op_plus_uconst(23),
- Operation::PlusConstant(23),
- read::Operation::PlusConstant { value: 23 },
- ),
- (
- &|x| x.op(constants::DW_OP_shl),
- Operation::Simple(constants::DW_OP_shl),
- read::Operation::Shl,
- ),
- (
- &|x| x.op(constants::DW_OP_shr),
- Operation::Simple(constants::DW_OP_shr),
- read::Operation::Shr,
- ),
- (
- &|x| x.op(constants::DW_OP_shra),
- Operation::Simple(constants::DW_OP_shra),
- read::Operation::Shra,
- ),
- (
- &|x| x.op(constants::DW_OP_xor),
- Operation::Simple(constants::DW_OP_xor),
- read::Operation::Xor,
- ),
- (
- &|x| x.op(constants::DW_OP_eq),
- Operation::Simple(constants::DW_OP_eq),
- read::Operation::Eq,
- ),
- (
- &|x| x.op(constants::DW_OP_ge),
- Operation::Simple(constants::DW_OP_ge),
- read::Operation::Ge,
- ),
- (
- &|x| x.op(constants::DW_OP_gt),
- Operation::Simple(constants::DW_OP_gt),
- read::Operation::Gt,
- ),
- (
- &|x| x.op(constants::DW_OP_le),
- Operation::Simple(constants::DW_OP_le),
- read::Operation::Le,
- ),
- (
- &|x| x.op(constants::DW_OP_lt),
- Operation::Simple(constants::DW_OP_lt),
- read::Operation::Lt,
- ),
- (
- &|x| x.op(constants::DW_OP_ne),
- Operation::Simple(constants::DW_OP_ne),
- read::Operation::Ne,
- ),
- (
- &|x| x.op_constu(23),
- Operation::UnsignedConstant(23),
- read::Operation::UnsignedConstant { value: 23 },
- ),
- (
- &|x| x.op_consts(-23),
- Operation::SignedConstant(-23),
- read::Operation::SignedConstant { value: -23 },
- ),
- (
- &|x| x.op_reg(Register(23)),
- Operation::Register(Register(23)),
- read::Operation::Register {
- register: Register(23),
- },
- ),
- (
- &|x| x.op_reg(Register(123)),
- Operation::Register(Register(123)),
- read::Operation::Register {
- register: Register(123),
- },
- ),
- (
- &|x| x.op_breg(Register(23), 34),
- Operation::RegisterOffset(Register(23), 34),
- read::Operation::RegisterOffset {
- register: Register(23),
- offset: 34,
- base_type: read::UnitOffset(0),
- },
- ),
- (
- &|x| x.op_breg(Register(123), 34),
- Operation::RegisterOffset(Register(123), 34),
- read::Operation::RegisterOffset {
- register: Register(123),
- offset: 34,
- base_type: read::UnitOffset(0),
- },
- ),
- (
- &|x| x.op_regval_type(Register(23), entry_id),
- Operation::RegisterType(Register(23), entry_id),
- read::Operation::RegisterOffset {
- register: Register(23),
- offset: 0,
- base_type: entry_offset,
- },
- ),
- (
- &|x| x.op_fbreg(34),
- Operation::FrameOffset(34),
- read::Operation::FrameOffset { offset: 34 },
- ),
- (
- &|x| x.op(constants::DW_OP_nop),
- Operation::Simple(constants::DW_OP_nop),
- read::Operation::Nop,
- ),
- (
- &|x| x.op(constants::DW_OP_push_object_address),
- Operation::Simple(constants::DW_OP_push_object_address),
- read::Operation::PushObjectAddress,
- ),
- (
- &|x| x.op_call(entry_id),
- Operation::Call(entry_id),
- read::Operation::Call {
- offset: read::DieReference::UnitRef(entry_offset),
- },
- ),
- (
- &|x| x.op_call_ref(reference),
- Operation::CallRef(reference),
- read::Operation::Call {
- offset: read::DieReference::DebugInfoRef(debug_info_offset),
- },
- ),
- (
- &|x| x.op(constants::DW_OP_form_tls_address),
- Operation::Simple(constants::DW_OP_form_tls_address),
- read::Operation::TLS,
- ),
- (
- &|x| x.op(constants::DW_OP_call_frame_cfa),
- Operation::Simple(constants::DW_OP_call_frame_cfa),
- read::Operation::CallFrameCFA,
- ),
- (
- &|x| x.op_piece(23),
- Operation::Piece { size_in_bytes: 23 },
- read::Operation::Piece {
- size_in_bits: 23 * 8,
- bit_offset: None,
- },
- ),
- (
- &|x| x.op_bit_piece(23, 34),
- Operation::BitPiece {
- size_in_bits: 23,
- bit_offset: 34,
- },
- read::Operation::Piece {
- size_in_bits: 23,
- bit_offset: Some(34),
- },
- ),
- (
- &|x| x.op_implicit_value(vec![23].into()),
- Operation::ImplicitValue(vec![23].into()),
- read::Operation::ImplicitValue {
- data: read::EndianSlice::new(&[23], LittleEndian),
- },
- ),
- (
- &|x| x.op(constants::DW_OP_stack_value),
- Operation::Simple(constants::DW_OP_stack_value),
- read::Operation::StackValue,
- ),
- (
- &|x| x.op_implicit_pointer(reference, 23),
- Operation::ImplicitPointer {
- entry: reference,
- byte_offset: 23,
- },
- read::Operation::ImplicitPointer {
- value: debug_info_offset,
- byte_offset: 23,
- },
- ),
- (
- &|x| x.op_entry_value(reg_expression.clone()),
- Operation::EntryValue(reg_expression.clone()),
- read::Operation::EntryValue {
- expression: read::EndianSlice::new(
- &[constants::DW_OP_reg23.0],
- LittleEndian,
- ),
- },
- ),
- (
- &|x| x.op_gnu_parameter_ref(entry_id),
- Operation::ParameterRef(entry_id),
- read::Operation::ParameterRef {
- offset: entry_offset,
- },
- ),
- (
- &|x| x.op_addr(Address::Constant(23)),
- Operation::Address(Address::Constant(23)),
- read::Operation::Address { address: 23 },
- ),
- (
- &|x| x.op_const_type(entry_id, vec![23].into()),
- Operation::ConstantType(entry_id, vec![23].into()),
- read::Operation::TypedLiteral {
- base_type: entry_offset,
- value: read::EndianSlice::new(&[23], LittleEndian),
- },
- ),
- (
- &|x| x.op_convert(None),
- Operation::Convert(None),
- read::Operation::Convert {
- base_type: read::UnitOffset(0),
- },
- ),
- (
- &|x| x.op_convert(Some(entry_id)),
- Operation::Convert(Some(entry_id)),
- read::Operation::Convert {
- base_type: entry_offset,
- },
- ),
- (
- &|x| x.op_reinterpret(None),
- Operation::Reinterpret(None),
- read::Operation::Reinterpret {
- base_type: read::UnitOffset(0),
- },
- ),
- (
- &|x| x.op_reinterpret(Some(entry_id)),
- Operation::Reinterpret(Some(entry_id)),
- read::Operation::Reinterpret {
- base_type: entry_offset,
- },
- ),
- (
- &|x| x.op_wasm_local(1000),
- Operation::WasmLocal(1000),
- read::Operation::WasmLocal { index: 1000 },
- ),
- (
- &|x| x.op_wasm_global(1000),
- Operation::WasmGlobal(1000),
- read::Operation::WasmGlobal { index: 1000 },
- ),
- (
- &|x| x.op_wasm_stack(1000),
- Operation::WasmStack(1000),
- read::Operation::WasmStack { index: 1000 },
- ),
- ];
-
- let mut expression = Expression::new();
- let start_index = expression.next_index();
- for (f, o, _) in operations {
- f(&mut expression);
- assert_eq!(expression.operations.last(), Some(o));
- }
-
- let bra_index = expression.op_bra();
- let skip_index = expression.op_skip();
- expression.op(constants::DW_OP_nop);
- let end_index = expression.next_index();
- expression.set_target(bra_index, start_index);
- expression.set_target(skip_index, end_index);
-
- let mut w = EndianVec::new(LittleEndian);
- let mut refs = Vec::new();
- expression
- .write(&mut w, Some(&mut refs), encoding, Some(&unit_offsets))
- .unwrap();
- for r in &refs {
- assert_eq!(r.unit, unit_id);
- assert_eq!(r.entry, entry_id);
- w.write_offset_at(
- r.offset,
- debug_info_offset.0,
- SectionId::DebugInfo,
- r.size,
- )
- .unwrap();
- }
-
- let read_expression =
- read::Expression(read::EndianSlice::new(w.slice(), LittleEndian));
- let mut read_operations = read_expression.operations(encoding);
- for (_, _, operation) in operations {
- assert_eq!(read_operations.next(), Ok(Some(*operation)));
- }
-
- // 4 = DW_OP_skip + i16 + DW_OP_nop
- assert_eq!(
- read_operations.next(),
- Ok(Some(read::Operation::Bra {
- target: -(w.len() as i16) + 4
- }))
- );
- // 1 = DW_OP_nop
- assert_eq!(
- read_operations.next(),
- Ok(Some(read::Operation::Skip { target: 1 }))
- );
- assert_eq!(read_operations.next(), Ok(Some(read::Operation::Nop)));
- assert_eq!(read_operations.next(), Ok(None));
-
- // Fake the unit.
- let unit = read::Unit {
- header: read::UnitHeader::new(
- encoding,
- 0,
- read::UnitType::Compilation,
- DebugAbbrevOffset(0),
- DebugInfoOffset(0).into(),
- read::EndianSlice::new(&[], LittleEndian),
- ),
- abbreviations: Arc::new(read::Abbreviations::default()),
- name: None,
- comp_dir: None,
- low_pc: 0,
- str_offsets_base: DebugStrOffsetsBase(0),
- addr_base: DebugAddrBase(0),
- loclists_base: DebugLocListsBase(0),
- rnglists_base: DebugRngListsBase(0),
- line_program: None,
- dwo_id: None,
- };
-
- let mut entry_ids = HashMap::new();
- entry_ids.insert(debug_info_offset.into(), (unit_id, entry_id));
- let convert_expression = Expression::from(
- read_expression,
- encoding,
- None, /* dwarf */
- Some(&unit),
- Some(&entry_ids),
- &|address| Some(Address::Constant(address)),
- )
- .unwrap();
- let mut convert_operations = convert_expression.operations.iter();
- for (_, operation, _) in operations {
- assert_eq!(convert_operations.next(), Some(operation));
- }
- assert_eq!(
- convert_operations.next(),
- Some(&Operation::Branch(start_index))
- );
- assert_eq!(convert_operations.next(), Some(&Operation::Skip(end_index)));
- assert_eq!(
- convert_operations.next(),
- Some(&Operation::Simple(constants::DW_OP_nop))
- );
- }
- }
- }
- }
-}