gimli/write/
op.rs

1use alloc::boxed::Box;
2use alloc::vec::Vec;
3
4use crate::common::{Encoding, Register};
5use crate::constants::{self, DwOp};
6use crate::leb128::write::{sleb128_size, uleb128_size};
7use crate::write::{
8    Address, DebugInfoReference, Error, Reference, Result, UnitEntryId, UnitOffsets, Writer,
9};
10
11/// The bytecode for a DWARF expression or location description.
12#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
13pub struct Expression {
14    operations: Vec<Operation>,
15}
16
17impl Expression {
18    /// Create an empty expression.
19    #[inline]
20    pub fn new() -> Self {
21        Self::default()
22    }
23
24    /// Create an expression from raw bytecode.
25    ///
26    /// This does not support operations that require references, such as `DW_OP_addr`.
27    #[inline]
28    pub fn raw(bytecode: Vec<u8>) -> Self {
29        Expression {
30            operations: vec![Operation::Raw(bytecode)],
31        }
32    }
33
34    /// Add an operation to the expression.
35    ///
36    /// This should only be used for operations that have no explicit operands.
37    pub fn op(&mut self, opcode: DwOp) {
38        self.operations.push(Operation::Simple(opcode));
39    }
40
41    /// Add a `DW_OP_addr` operation to the expression.
42    pub fn op_addr(&mut self, address: Address) {
43        self.operations.push(Operation::Address(address));
44    }
45
46    /// Add a `DW_OP_constu` operation to the expression.
47    ///
48    /// This may be emitted as a smaller equivalent operation.
49    pub fn op_constu(&mut self, value: u64) {
50        self.operations.push(Operation::UnsignedConstant(value));
51    }
52
53    /// Add a `DW_OP_consts` operation to the expression.
54    ///
55    /// This may be emitted as a smaller equivalent operation.
56    pub fn op_consts(&mut self, value: i64) {
57        self.operations.push(Operation::SignedConstant(value));
58    }
59
60    /// Add a `DW_OP_const_type` or `DW_OP_GNU_const_type` operation to the expression.
61    pub fn op_const_type(&mut self, base: UnitEntryId, value: Box<[u8]>) {
62        self.operations.push(Operation::ConstantType(base, value));
63    }
64
65    /// Add a `DW_OP_fbreg` operation to the expression.
66    pub fn op_fbreg(&mut self, offset: i64) {
67        self.operations.push(Operation::FrameOffset(offset));
68    }
69
70    /// Add a `DW_OP_bregx` operation to the expression.
71    ///
72    /// This may be emitted as a smaller equivalent operation.
73    pub fn op_breg(&mut self, register: Register, offset: i64) {
74        self.operations
75            .push(Operation::RegisterOffset(register, offset));
76    }
77
78    /// Add a `DW_OP_regval_type` or `DW_OP_GNU_regval_type` operation to the expression.
79    ///
80    /// This may be emitted as a smaller equivalent operation.
81    pub fn op_regval_type(&mut self, register: Register, base: UnitEntryId) {
82        self.operations
83            .push(Operation::RegisterType(register, base));
84    }
85
86    /// Add a `DW_OP_pick` operation to the expression.
87    ///
88    /// This may be emitted as a `DW_OP_dup` or `DW_OP_over` operation.
89    pub fn op_pick(&mut self, index: u8) {
90        self.operations.push(Operation::Pick(index));
91    }
92
93    /// Add a `DW_OP_deref` operation to the expression.
94    pub fn op_deref(&mut self) {
95        self.operations.push(Operation::Deref { space: false });
96    }
97
98    /// Add a `DW_OP_xderef` operation to the expression.
99    pub fn op_xderef(&mut self) {
100        self.operations.push(Operation::Deref { space: true });
101    }
102
103    /// Add a `DW_OP_deref_size` operation to the expression.
104    pub fn op_deref_size(&mut self, size: u8) {
105        self.operations
106            .push(Operation::DerefSize { size, space: false });
107    }
108
109    /// Add a `DW_OP_xderef_size` operation to the expression.
110    pub fn op_xderef_size(&mut self, size: u8) {
111        self.operations
112            .push(Operation::DerefSize { size, space: true });
113    }
114
115    /// Add a `DW_OP_deref_type` or `DW_OP_GNU_deref_type` operation to the expression.
116    pub fn op_deref_type(&mut self, size: u8, base: UnitEntryId) {
117        self.operations.push(Operation::DerefType {
118            size,
119            base,
120            space: false,
121        });
122    }
123
124    /// Add a `DW_OP_xderef_type` operation to the expression.
125    pub fn op_xderef_type(&mut self, size: u8, base: UnitEntryId) {
126        self.operations.push(Operation::DerefType {
127            size,
128            base,
129            space: true,
130        });
131    }
132
133    /// Add a `DW_OP_plus_uconst` operation to the expression.
134    pub fn op_plus_uconst(&mut self, value: u64) {
135        self.operations.push(Operation::PlusConstant(value));
136    }
137
138    /// Add a `DW_OP_skip` operation to the expression.
139    ///
140    /// Returns the index of the operation. The caller must call `set_target` with
141    /// this index to set the target of the branch.
142    pub fn op_skip(&mut self) -> usize {
143        let index = self.next_index();
144        self.operations.push(Operation::Skip(!0));
145        index
146    }
147
148    /// Add a `DW_OP_bra` operation to the expression.
149    ///
150    /// Returns the index of the operation. The caller must call `set_target` with
151    /// this index to set the target of the branch.
152    pub fn op_bra(&mut self) -> usize {
153        let index = self.next_index();
154        self.operations.push(Operation::Branch(!0));
155        index
156    }
157
158    /// Return the index that will be assigned to the next operation.
159    ///
160    /// This can be passed to `set_target`.
161    #[inline]
162    pub fn next_index(&self) -> usize {
163        self.operations.len()
164    }
165
166    /// Set the target of a `DW_OP_skip` or `DW_OP_bra` operation .
167    pub fn set_target(&mut self, operation: usize, new_target: usize) {
168        debug_assert!(new_target <= self.next_index());
169        debug_assert_ne!(operation, new_target);
170        match self.operations[operation] {
171            Operation::Skip(ref mut target) | Operation::Branch(ref mut target) => {
172                *target = new_target;
173            }
174            _ => unimplemented!(),
175        }
176    }
177
178    /// Add a `DW_OP_call4` operation to the expression.
179    pub fn op_call(&mut self, entry: UnitEntryId) {
180        self.operations.push(Operation::Call(entry));
181    }
182
183    /// Add a `DW_OP_call_ref` operation to the expression.
184    pub fn op_call_ref(&mut self, entry: Reference) {
185        self.operations.push(Operation::CallRef(entry));
186    }
187
188    /// Add a `DW_OP_convert` or `DW_OP_GNU_convert` operation to the expression.
189    ///
190    /// `base` is the DIE of the base type, or `None` for the generic type.
191    pub fn op_convert(&mut self, base: Option<UnitEntryId>) {
192        self.operations.push(Operation::Convert(base));
193    }
194
195    /// Add a `DW_OP_reinterpret` or `DW_OP_GNU_reinterpret` operation to the expression.
196    ///
197    /// `base` is the DIE of the base type, or `None` for the generic type.
198    pub fn op_reinterpret(&mut self, base: Option<UnitEntryId>) {
199        self.operations.push(Operation::Reinterpret(base));
200    }
201
202    /// Add a `DW_OP_entry_value` or `DW_OP_GNU_entry_value` operation to the expression.
203    pub fn op_entry_value(&mut self, expression: Expression) {
204        self.operations.push(Operation::EntryValue(expression));
205    }
206
207    /// Add a `DW_OP_regx` operation to the expression.
208    ///
209    /// This may be emitted as a smaller equivalent operation.
210    pub fn op_reg(&mut self, register: Register) {
211        self.operations.push(Operation::Register(register));
212    }
213
214    /// Add a `DW_OP_implicit_value` operation to the expression.
215    pub fn op_implicit_value(&mut self, data: Box<[u8]>) {
216        self.operations.push(Operation::ImplicitValue(data));
217    }
218
219    /// Add a `DW_OP_implicit_pointer` or `DW_OP_GNU_implicit_pointer` operation to the expression.
220    pub fn op_implicit_pointer(&mut self, entry: Reference, byte_offset: i64) {
221        self.operations
222            .push(Operation::ImplicitPointer { entry, byte_offset });
223    }
224
225    /// Add a `DW_OP_piece` operation to the expression.
226    pub fn op_piece(&mut self, size_in_bytes: u64) {
227        self.operations.push(Operation::Piece { size_in_bytes });
228    }
229
230    /// Add a `DW_OP_bit_piece` operation to the expression.
231    pub fn op_bit_piece(&mut self, size_in_bits: u64, bit_offset: u64) {
232        self.operations.push(Operation::BitPiece {
233            size_in_bits,
234            bit_offset,
235        });
236    }
237
238    /// Add a `DW_OP_GNU_parameter_ref` operation to the expression.
239    pub fn op_gnu_parameter_ref(&mut self, entry: UnitEntryId) {
240        self.operations.push(Operation::ParameterRef(entry));
241    }
242
243    /// Add a `DW_OP_WASM_location 0x0` operation to the expression.
244    pub fn op_wasm_local(&mut self, index: u32) {
245        self.operations.push(Operation::WasmLocal(index));
246    }
247
248    /// Add a `DW_OP_WASM_location 0x1` operation to the expression.
249    pub fn op_wasm_global(&mut self, index: u32) {
250        self.operations.push(Operation::WasmGlobal(index));
251    }
252
253    /// Add a `DW_OP_WASM_location 0x2` operation to the expression.
254    pub fn op_wasm_stack(&mut self, index: u32) {
255        self.operations.push(Operation::WasmStack(index));
256    }
257
258    pub(crate) fn size(
259        &self,
260        encoding: Encoding,
261        unit_offsets: Option<&UnitOffsets>,
262    ) -> Result<usize> {
263        let mut size = 0;
264        for operation in &self.operations {
265            size += operation.size(encoding, unit_offsets)?;
266        }
267        Ok(size)
268    }
269
270    pub(crate) fn write<W: Writer>(
271        &self,
272        w: &mut W,
273        mut refs: Option<&mut Vec<DebugInfoReference>>,
274        encoding: Encoding,
275        unit_offsets: Option<&UnitOffsets>,
276    ) -> Result<()> {
277        // TODO: only calculate offsets if needed?
278        let mut offsets = Vec::with_capacity(self.operations.len());
279        let mut offset = w.len();
280        for operation in &self.operations {
281            offsets.push(offset);
282            offset += operation.size(encoding, unit_offsets)?;
283        }
284        offsets.push(offset);
285        for (operation, offset) in self.operations.iter().zip(offsets.iter().copied()) {
286            debug_assert_eq!(w.len(), offset);
287            operation.write(w, refs.as_deref_mut(), encoding, unit_offsets, &offsets)?;
288        }
289        debug_assert_eq!(w.len(), offset);
290        Ok(())
291    }
292}
293
294/// A single DWARF operation.
295//
296// This type is intentionally not public so that we can change the
297// representation of expressions as needed.
298//
299// Variants are listed in the order they appear in Section 2.5.
300#[derive(Debug, Clone, PartialEq, Eq, Hash)]
301enum Operation {
302    /// Raw bytecode.
303    ///
304    /// Does not support references.
305    Raw(Vec<u8>),
306    /// An operation that has no explicit operands.
307    ///
308    /// Represents:
309    /// - `DW_OP_drop`, `DW_OP_swap`, `DW_OP_rot`
310    /// - `DW_OP_push_object_address`, `DW_OP_form_tls_address`, `DW_OP_call_frame_cfa`
311    /// - `DW_OP_abs`, `DW_OP_and`, `DW_OP_div`, `DW_OP_minus`, `DW_OP_mod`, `DW_OP_mul`,
312    ///   `DW_OP_neg`, `DW_OP_not`, `DW_OP_or`, `DW_OP_plus`, `DW_OP_shl`, `DW_OP_shr`,
313    ///   `DW_OP_shra`, `DW_OP_xor`
314    /// - `DW_OP_le`, `DW_OP_ge`, `DW_OP_eq`, `DW_OP_lt`, `DW_OP_gt`, `DW_OP_ne`
315    /// - `DW_OP_nop`
316    /// - `DW_OP_stack_value`
317    Simple(DwOp),
318    /// Relocate the address if needed, and push it on the stack.
319    ///
320    /// Represents `DW_OP_addr`.
321    Address(Address),
322    /// Push an unsigned constant value on the stack.
323    ///
324    /// Represents `DW_OP_constu`.
325    UnsignedConstant(u64),
326    /// Push a signed constant value on the stack.
327    ///
328    /// Represents `DW_OP_consts`.
329    SignedConstant(i64),
330    /* TODO: requires .debug_addr write support
331    /// Read the address at the given index in `.debug_addr, relocate the address if needed,
332    /// and push it on the stack.
333    ///
334    /// Represents `DW_OP_addrx`.
335    AddressIndex(DebugAddrIndex<Offset>),
336    /// Read the address at the given index in `.debug_addr, and push it on the stack.
337    /// Do not relocate the address.
338    ///
339    /// Represents `DW_OP_constx`.
340    ConstantIndex(DebugAddrIndex<Offset>),
341    */
342    /// Interpret the value bytes as a constant of a given type, and push it on the stack.
343    ///
344    /// Represents `DW_OP_const_type`.
345    ConstantType(UnitEntryId, Box<[u8]>),
346    /// Compute the frame base (using `DW_AT_frame_base`), add the
347    /// given offset, and then push the resulting sum on the stack.
348    ///
349    /// Represents `DW_OP_fbreg`.
350    FrameOffset(i64),
351    /// Find the contents of the given register, add the offset, and then
352    /// push the resulting sum on the stack.
353    ///
354    /// Represents `DW_OP_bregx`.
355    RegisterOffset(Register, i64),
356    /// Interpret the contents of the given register as a value of the given type,
357    /// and push it on the stack.
358    ///
359    /// Represents `DW_OP_regval_type`.
360    RegisterType(Register, UnitEntryId),
361    /// Copy the item at a stack index and push it on top of the stack.
362    ///
363    /// Represents `DW_OP_pick`, `DW_OP_dup`, and `DW_OP_over`.
364    Pick(u8),
365    /// Pop the topmost value of the stack, dereference it, and push the
366    /// resulting value.
367    ///
368    /// Represents `DW_OP_deref` and `DW_OP_xderef`.
369    Deref {
370        /// True if the dereference operation takes an address space
371        /// argument from the stack; false otherwise.
372        space: bool,
373    },
374    /// Pop the topmost value of the stack, dereference it to obtain a value
375    /// of the given size, and push the resulting value.
376    ///
377    /// Represents `DW_OP_deref_size` and `DW_OP_xderef_size`.
378    DerefSize {
379        /// True if the dereference operation takes an address space
380        /// argument from the stack; false otherwise.
381        space: bool,
382        /// The size of the data to dereference.
383        size: u8,
384    },
385    /// Pop the topmost value of the stack, dereference it to obtain a value
386    /// of the given type, and push the resulting value.
387    ///
388    /// Represents `DW_OP_deref_type` and `DW_OP_xderef_type`.
389    DerefType {
390        /// True if the dereference operation takes an address space
391        /// argument from the stack; false otherwise.
392        space: bool,
393        /// The size of the data to dereference.
394        size: u8,
395        /// The DIE of the base type, or `None` for the generic type.
396        base: UnitEntryId,
397    },
398    /// Add an unsigned constant to the topmost value on the stack.
399    ///
400    /// Represents `DW_OP_plus_uconst`.
401    PlusConstant(u64),
402    /// Unconditional branch to the target location.
403    ///
404    /// The value is the index within the expression of the operation to branch to.
405    /// This will be converted to a relative offset when writing.
406    ///
407    /// Represents `DW_OP_skip`.
408    Skip(usize),
409    /// Branch to the target location if the top of stack is nonzero.
410    ///
411    /// The value is the index within the expression of the operation to branch to.
412    /// This will be converted to a relative offset when writing.
413    ///
414    /// Represents `DW_OP_bra`.
415    Branch(usize),
416    /// Evaluate a DWARF expression as a subroutine.
417    ///
418    /// The expression comes from the `DW_AT_location` attribute of the indicated DIE.
419    ///
420    /// Represents `DW_OP_call4`.
421    Call(UnitEntryId),
422    /// Evaluate an external DWARF expression as a subroutine.
423    ///
424    /// The expression comes from the `DW_AT_location` attribute of the indicated DIE,
425    /// which may be in another compilation unit or shared object.
426    ///
427    /// Represents `DW_OP_call_ref`.
428    CallRef(Reference),
429    /// Pop the top stack entry, convert it to a different type, and push it on the stack.
430    ///
431    /// Represents `DW_OP_convert`.
432    Convert(Option<UnitEntryId>),
433    /// Pop the top stack entry, reinterpret the bits in its value as a different type,
434    /// and push it on the stack.
435    ///
436    /// Represents `DW_OP_reinterpret`.
437    Reinterpret(Option<UnitEntryId>),
438    /// Evaluate an expression at the entry to the current subprogram, and push it on the stack.
439    ///
440    /// Represents `DW_OP_entry_value`.
441    EntryValue(Expression),
442    // FIXME: EntryRegister
443    /// Indicate that this piece's location is in the given register.
444    ///
445    /// Completes the piece or expression.
446    ///
447    /// Represents `DW_OP_regx`.
448    Register(Register),
449    /// The object has no location, but has a known constant value.
450    ///
451    /// Completes the piece or expression.
452    ///
453    /// Represents `DW_OP_implicit_value`.
454    ImplicitValue(Box<[u8]>),
455    /// The object is a pointer to a value which has no actual location, such as
456    /// an implicit value or a stack value.
457    ///
458    /// Completes the piece or expression.
459    ///
460    /// Represents `DW_OP_implicit_pointer`.
461    ImplicitPointer {
462        /// The DIE of the value that this is an implicit pointer into.
463        entry: Reference,
464        /// The byte offset into the value that the implicit pointer points to.
465        byte_offset: i64,
466    },
467    /// Terminate a piece.
468    ///
469    /// Represents `DW_OP_piece`.
470    Piece {
471        /// The size of this piece in bytes.
472        size_in_bytes: u64,
473    },
474    /// Terminate a piece with a size in bits.
475    ///
476    /// Represents `DW_OP_bit_piece`.
477    BitPiece {
478        /// The size of this piece in bits.
479        size_in_bits: u64,
480        /// The bit offset of this piece.
481        bit_offset: u64,
482    },
483    /// This represents a parameter that was optimized out.
484    ///
485    /// The entry is the definition of the parameter, and is matched to
486    /// the `DW_TAG_GNU_call_site_parameter` in the caller that also
487    /// points to the same definition of the parameter.
488    ///
489    /// Represents `DW_OP_GNU_parameter_ref`.
490    ParameterRef(UnitEntryId),
491    /// The index of a local in the currently executing function.
492    ///
493    /// Represents `DW_OP_WASM_location 0x00`.
494    WasmLocal(u32),
495    /// The index of a global.
496    ///
497    /// Represents `DW_OP_WASM_location 0x01`.
498    WasmGlobal(u32),
499    /// The index of an item on the operand stack.
500    ///
501    /// Represents `DW_OP_WASM_location 0x02`.
502    WasmStack(u32),
503}
504
505impl Operation {
506    fn size(&self, encoding: Encoding, unit_offsets: Option<&UnitOffsets>) -> Result<usize> {
507        let base_size = |entry| match unit_offsets {
508            Some(offsets) => offsets
509                .unit_offset(entry)
510                .map(uleb128_size)
511                .ok_or(Error::UnsupportedExpressionForwardReference),
512            None => Err(Error::UnsupportedCfiExpressionReference),
513        };
514        Ok(1 + match *self {
515            Operation::Raw(ref bytecode) => return Ok(bytecode.len()),
516            Operation::Simple(_) => 0,
517            Operation::Address(_) => encoding.address_size as usize,
518            Operation::UnsignedConstant(value) => {
519                if value < 32 {
520                    0
521                } else {
522                    uleb128_size(value)
523                }
524            }
525            Operation::SignedConstant(value) => sleb128_size(value),
526            Operation::ConstantType(base, ref value) => base_size(base)? + 1 + value.len(),
527            Operation::FrameOffset(offset) => sleb128_size(offset),
528            Operation::RegisterOffset(register, offset) => {
529                if register.0 < 32 {
530                    sleb128_size(offset)
531                } else {
532                    uleb128_size(register.0.into()) + sleb128_size(offset)
533                }
534            }
535            Operation::RegisterType(register, base) => {
536                uleb128_size(register.0.into()) + base_size(base)?
537            }
538            Operation::Pick(index) => {
539                if index > 1 {
540                    1
541                } else {
542                    0
543                }
544            }
545            Operation::Deref { .. } => 0,
546            Operation::DerefSize { .. } => 1,
547            Operation::DerefType { base, .. } => 1 + base_size(base)?,
548            Operation::PlusConstant(value) => uleb128_size(value),
549            Operation::Skip(_) => 2,
550            Operation::Branch(_) => 2,
551            Operation::Call(_) => 4,
552            Operation::CallRef(_) => encoding.format.word_size() as usize,
553            Operation::Convert(base) => match base {
554                Some(base) => base_size(base)?,
555                None => 1,
556            },
557            Operation::Reinterpret(base) => match base {
558                Some(base) => base_size(base)?,
559                None => 1,
560            },
561            Operation::EntryValue(ref expression) => {
562                let length = expression.size(encoding, unit_offsets)?;
563                uleb128_size(length as u64) + length
564            }
565            Operation::Register(register) => {
566                if register.0 < 32 {
567                    0
568                } else {
569                    uleb128_size(register.0.into())
570                }
571            }
572            Operation::ImplicitValue(ref data) => uleb128_size(data.len() as u64) + data.len(),
573            Operation::ImplicitPointer { byte_offset, .. } => {
574                let size = if encoding.version == 2 {
575                    encoding.address_size
576                } else {
577                    encoding.format.word_size()
578                };
579                size as usize + sleb128_size(byte_offset)
580            }
581            Operation::Piece { size_in_bytes } => uleb128_size(size_in_bytes),
582            Operation::BitPiece {
583                size_in_bits,
584                bit_offset,
585            } => uleb128_size(size_in_bits) + uleb128_size(bit_offset),
586            Operation::ParameterRef(_) => 4,
587            Operation::WasmLocal(index)
588            | Operation::WasmGlobal(index)
589            | Operation::WasmStack(index) => 1 + uleb128_size(index.into()),
590        })
591    }
592
593    pub(crate) fn write<W: Writer>(
594        &self,
595        w: &mut W,
596        refs: Option<&mut Vec<DebugInfoReference>>,
597        encoding: Encoding,
598        unit_offsets: Option<&UnitOffsets>,
599        offsets: &[usize],
600    ) -> Result<()> {
601        let entry_offset = |entry| match unit_offsets {
602            Some(offsets) => offsets
603                .unit_offset(entry)
604                .ok_or(Error::UnsupportedExpressionForwardReference),
605            None => Err(Error::UnsupportedCfiExpressionReference),
606        };
607        match *self {
608            Operation::Raw(ref bytecode) => w.write(bytecode)?,
609            Operation::Simple(opcode) => w.write_u8(opcode.0)?,
610            Operation::Address(address) => {
611                w.write_u8(constants::DW_OP_addr.0)?;
612                w.write_address(address, encoding.address_size)?;
613            }
614            Operation::UnsignedConstant(value) => {
615                if value < 32 {
616                    w.write_u8(constants::DW_OP_lit0.0 + value as u8)?;
617                } else {
618                    w.write_u8(constants::DW_OP_constu.0)?;
619                    w.write_uleb128(value)?;
620                }
621            }
622            Operation::SignedConstant(value) => {
623                w.write_u8(constants::DW_OP_consts.0)?;
624                w.write_sleb128(value)?;
625            }
626            Operation::ConstantType(base, ref value) => {
627                if encoding.version >= 5 {
628                    w.write_u8(constants::DW_OP_const_type.0)?;
629                } else {
630                    w.write_u8(constants::DW_OP_GNU_const_type.0)?;
631                }
632                w.write_uleb128(entry_offset(base)?)?;
633                w.write_udata(value.len() as u64, 1)?;
634                w.write(value)?;
635            }
636            Operation::FrameOffset(offset) => {
637                w.write_u8(constants::DW_OP_fbreg.0)?;
638                w.write_sleb128(offset)?;
639            }
640            Operation::RegisterOffset(register, offset) => {
641                if register.0 < 32 {
642                    w.write_u8(constants::DW_OP_breg0.0 + register.0 as u8)?;
643                } else {
644                    w.write_u8(constants::DW_OP_bregx.0)?;
645                    w.write_uleb128(register.0.into())?;
646                }
647                w.write_sleb128(offset)?;
648            }
649            Operation::RegisterType(register, base) => {
650                if encoding.version >= 5 {
651                    w.write_u8(constants::DW_OP_regval_type.0)?;
652                } else {
653                    w.write_u8(constants::DW_OP_GNU_regval_type.0)?;
654                }
655                w.write_uleb128(register.0.into())?;
656                w.write_uleb128(entry_offset(base)?)?;
657            }
658            Operation::Pick(index) => match index {
659                0 => w.write_u8(constants::DW_OP_dup.0)?,
660                1 => w.write_u8(constants::DW_OP_over.0)?,
661                _ => {
662                    w.write_u8(constants::DW_OP_pick.0)?;
663                    w.write_u8(index)?;
664                }
665            },
666            Operation::Deref { space } => {
667                if space {
668                    w.write_u8(constants::DW_OP_xderef.0)?;
669                } else {
670                    w.write_u8(constants::DW_OP_deref.0)?;
671                }
672            }
673            Operation::DerefSize { space, size } => {
674                if space {
675                    w.write_u8(constants::DW_OP_xderef_size.0)?;
676                } else {
677                    w.write_u8(constants::DW_OP_deref_size.0)?;
678                }
679                w.write_u8(size)?;
680            }
681            Operation::DerefType { space, size, base } => {
682                if space {
683                    w.write_u8(constants::DW_OP_xderef_type.0)?;
684                } else {
685                    if encoding.version >= 5 {
686                        w.write_u8(constants::DW_OP_deref_type.0)?;
687                    } else {
688                        w.write_u8(constants::DW_OP_GNU_deref_type.0)?;
689                    }
690                }
691                w.write_u8(size)?;
692                w.write_uleb128(entry_offset(base)?)?;
693            }
694            Operation::PlusConstant(value) => {
695                w.write_u8(constants::DW_OP_plus_uconst.0)?;
696                w.write_uleb128(value)?;
697            }
698            Operation::Skip(target) => {
699                w.write_u8(constants::DW_OP_skip.0)?;
700                let offset = offsets[target] as i64 - (w.len() as i64 + 2);
701                w.write_sdata(offset, 2)?;
702            }
703            Operation::Branch(target) => {
704                w.write_u8(constants::DW_OP_bra.0)?;
705                let offset = offsets[target] as i64 - (w.len() as i64 + 2);
706                w.write_sdata(offset, 2)?;
707            }
708            Operation::Call(entry) => {
709                w.write_u8(constants::DW_OP_call4.0)?;
710                // TODO: this probably won't work in practice, because we may
711                // only know the offsets of base type DIEs at this point.
712                w.write_udata(entry_offset(entry)?, 4)?;
713            }
714            Operation::CallRef(entry) => {
715                w.write_u8(constants::DW_OP_call_ref.0)?;
716                let size = encoding.format.word_size();
717                match entry {
718                    Reference::Symbol(symbol) => w.write_reference(symbol, size)?,
719                    Reference::Entry(unit, entry) => {
720                        let refs = refs.ok_or(Error::InvalidReference)?;
721                        refs.push(DebugInfoReference {
722                            offset: w.len(),
723                            unit,
724                            entry,
725                            size,
726                        });
727                        w.write_udata(0, size)?;
728                    }
729                }
730            }
731            Operation::Convert(base) => {
732                if encoding.version >= 5 {
733                    w.write_u8(constants::DW_OP_convert.0)?;
734                } else {
735                    w.write_u8(constants::DW_OP_GNU_convert.0)?;
736                }
737                match base {
738                    Some(base) => w.write_uleb128(entry_offset(base)?)?,
739                    None => w.write_u8(0)?,
740                }
741            }
742            Operation::Reinterpret(base) => {
743                if encoding.version >= 5 {
744                    w.write_u8(constants::DW_OP_reinterpret.0)?;
745                } else {
746                    w.write_u8(constants::DW_OP_GNU_reinterpret.0)?;
747                }
748                match base {
749                    Some(base) => w.write_uleb128(entry_offset(base)?)?,
750                    None => w.write_u8(0)?,
751                }
752            }
753            Operation::EntryValue(ref expression) => {
754                if encoding.version >= 5 {
755                    w.write_u8(constants::DW_OP_entry_value.0)?;
756                } else {
757                    w.write_u8(constants::DW_OP_GNU_entry_value.0)?;
758                }
759                let length = expression.size(encoding, unit_offsets)?;
760                w.write_uleb128(length as u64)?;
761                expression.write(w, refs, encoding, unit_offsets)?;
762            }
763            Operation::Register(register) => {
764                if register.0 < 32 {
765                    w.write_u8(constants::DW_OP_reg0.0 + register.0 as u8)?;
766                } else {
767                    w.write_u8(constants::DW_OP_regx.0)?;
768                    w.write_uleb128(register.0.into())?;
769                }
770            }
771            Operation::ImplicitValue(ref data) => {
772                w.write_u8(constants::DW_OP_implicit_value.0)?;
773                w.write_uleb128(data.len() as u64)?;
774                w.write(data)?;
775            }
776            Operation::ImplicitPointer { entry, byte_offset } => {
777                if encoding.version >= 5 {
778                    w.write_u8(constants::DW_OP_implicit_pointer.0)?;
779                } else {
780                    w.write_u8(constants::DW_OP_GNU_implicit_pointer.0)?;
781                }
782                let size = if encoding.version == 2 {
783                    encoding.address_size
784                } else {
785                    encoding.format.word_size()
786                };
787                match entry {
788                    Reference::Symbol(symbol) => {
789                        w.write_reference(symbol, size)?;
790                    }
791                    Reference::Entry(unit, entry) => {
792                        let refs = refs.ok_or(Error::InvalidReference)?;
793                        refs.push(DebugInfoReference {
794                            offset: w.len(),
795                            unit,
796                            entry,
797                            size,
798                        });
799                        w.write_udata(0, size)?;
800                    }
801                }
802                w.write_sleb128(byte_offset)?;
803            }
804            Operation::Piece { size_in_bytes } => {
805                w.write_u8(constants::DW_OP_piece.0)?;
806                w.write_uleb128(size_in_bytes)?;
807            }
808            Operation::BitPiece {
809                size_in_bits,
810                bit_offset,
811            } => {
812                w.write_u8(constants::DW_OP_bit_piece.0)?;
813                w.write_uleb128(size_in_bits)?;
814                w.write_uleb128(bit_offset)?;
815            }
816            Operation::ParameterRef(entry) => {
817                w.write_u8(constants::DW_OP_GNU_parameter_ref.0)?;
818                w.write_udata(entry_offset(entry)?, 4)?;
819            }
820            Operation::WasmLocal(index) => {
821                w.write(&[constants::DW_OP_WASM_location.0, 0])?;
822                w.write_uleb128(index.into())?;
823            }
824            Operation::WasmGlobal(index) => {
825                w.write(&[constants::DW_OP_WASM_location.0, 1])?;
826                w.write_uleb128(index.into())?;
827            }
828            Operation::WasmStack(index) => {
829                w.write(&[constants::DW_OP_WASM_location.0, 2])?;
830                w.write_uleb128(index.into())?;
831            }
832        }
833        Ok(())
834    }
835}
836
837#[cfg(feature = "read")]
838pub(crate) mod convert {
839    use super::*;
840    use crate::common::UnitSectionOffset;
841    use crate::read::{self, Reader};
842    use crate::write::{ConvertError, ConvertResult, UnitId};
843    use std::collections::HashMap;
844
845    impl Expression {
846        /// Create an expression from the input expression.
847        pub fn from<R: Reader<Offset = usize>>(
848            from_expression: read::Expression<R>,
849            encoding: Encoding,
850            dwarf: Option<&read::Dwarf<R>>,
851            unit: Option<&read::Unit<R>>,
852            entry_ids: Option<&HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>>,
853            convert_address: &dyn Fn(u64) -> Option<Address>,
854        ) -> ConvertResult<Expression> {
855            let convert_unit_offset = |offset: read::UnitOffset| -> ConvertResult<_> {
856                let entry_ids = entry_ids.ok_or(ConvertError::UnsupportedOperation)?;
857                let unit = unit.ok_or(ConvertError::UnsupportedOperation)?;
858                let id = entry_ids
859                    .get(&offset.to_unit_section_offset(unit))
860                    .ok_or(ConvertError::InvalidUnitRef)?;
861                Ok(id.1)
862            };
863            let convert_debug_info_offset = |offset| -> ConvertResult<_> {
864                // TODO: support relocations
865                let entry_ids = entry_ids.ok_or(ConvertError::UnsupportedOperation)?;
866                let id = entry_ids
867                    .get(&UnitSectionOffset::DebugInfoOffset(offset))
868                    .ok_or(ConvertError::InvalidDebugInfoRef)?;
869                Ok(Reference::Entry(id.0, id.1))
870            };
871
872            // Calculate offsets for use in branch/skip operations.
873            let mut offsets = Vec::new();
874            let mut offset = 0;
875            let mut from_operations = from_expression.clone().operations(encoding);
876            while from_operations.next()?.is_some() {
877                offsets.push(offset);
878                offset = from_operations.offset_from(&from_expression);
879            }
880            offsets.push(from_expression.0.len());
881
882            let mut from_operations = from_expression.clone().operations(encoding);
883            let mut operations = Vec::new();
884            while let Some(from_operation) = from_operations.next()? {
885                let operation = match from_operation {
886                    read::Operation::Deref {
887                        base_type,
888                        size,
889                        space,
890                    } => {
891                        if base_type.0 != 0 {
892                            let base = convert_unit_offset(base_type)?;
893                            Operation::DerefType { space, size, base }
894                        } else if size != encoding.address_size {
895                            Operation::DerefSize { space, size }
896                        } else {
897                            Operation::Deref { space }
898                        }
899                    }
900                    read::Operation::Drop => Operation::Simple(constants::DW_OP_drop),
901                    read::Operation::Pick { index } => Operation::Pick(index),
902                    read::Operation::Swap => Operation::Simple(constants::DW_OP_swap),
903                    read::Operation::Rot => Operation::Simple(constants::DW_OP_rot),
904                    read::Operation::Abs => Operation::Simple(constants::DW_OP_abs),
905                    read::Operation::And => Operation::Simple(constants::DW_OP_and),
906                    read::Operation::Div => Operation::Simple(constants::DW_OP_div),
907                    read::Operation::Minus => Operation::Simple(constants::DW_OP_minus),
908                    read::Operation::Mod => Operation::Simple(constants::DW_OP_mod),
909                    read::Operation::Mul => Operation::Simple(constants::DW_OP_mul),
910                    read::Operation::Neg => Operation::Simple(constants::DW_OP_neg),
911                    read::Operation::Not => Operation::Simple(constants::DW_OP_not),
912                    read::Operation::Or => Operation::Simple(constants::DW_OP_or),
913                    read::Operation::Plus => Operation::Simple(constants::DW_OP_plus),
914                    read::Operation::PlusConstant { value } => Operation::PlusConstant(value),
915                    read::Operation::Shl => Operation::Simple(constants::DW_OP_shl),
916                    read::Operation::Shr => Operation::Simple(constants::DW_OP_shr),
917                    read::Operation::Shra => Operation::Simple(constants::DW_OP_shra),
918                    read::Operation::Xor => Operation::Simple(constants::DW_OP_xor),
919                    read::Operation::Eq => Operation::Simple(constants::DW_OP_eq),
920                    read::Operation::Ge => Operation::Simple(constants::DW_OP_ge),
921                    read::Operation::Gt => Operation::Simple(constants::DW_OP_gt),
922                    read::Operation::Le => Operation::Simple(constants::DW_OP_le),
923                    read::Operation::Lt => Operation::Simple(constants::DW_OP_lt),
924                    read::Operation::Ne => Operation::Simple(constants::DW_OP_ne),
925                    read::Operation::Bra { target } => {
926                        let offset = from_operations
927                            .offset_from(&from_expression)
928                            .wrapping_add(i64::from(target) as usize);
929                        let index = offsets
930                            .binary_search(&offset)
931                            .map_err(|_| ConvertError::InvalidBranchTarget)?;
932                        Operation::Branch(index)
933                    }
934                    read::Operation::Skip { target } => {
935                        let offset = from_operations
936                            .offset_from(&from_expression)
937                            .wrapping_add(i64::from(target) as usize);
938                        let index = offsets
939                            .binary_search(&offset)
940                            .map_err(|_| ConvertError::InvalidBranchTarget)?;
941                        Operation::Skip(index)
942                    }
943                    read::Operation::UnsignedConstant { value } => {
944                        Operation::UnsignedConstant(value)
945                    }
946                    read::Operation::SignedConstant { value } => Operation::SignedConstant(value),
947                    read::Operation::Register { register } => Operation::Register(register),
948                    read::Operation::RegisterOffset {
949                        register,
950                        offset,
951                        base_type,
952                    } => {
953                        if base_type.0 != 0 {
954                            Operation::RegisterType(register, convert_unit_offset(base_type)?)
955                        } else {
956                            Operation::RegisterOffset(register, offset)
957                        }
958                    }
959                    read::Operation::FrameOffset { offset } => Operation::FrameOffset(offset),
960                    read::Operation::Nop => Operation::Simple(constants::DW_OP_nop),
961                    read::Operation::PushObjectAddress => {
962                        Operation::Simple(constants::DW_OP_push_object_address)
963                    }
964                    read::Operation::Call { offset } => match offset {
965                        read::DieReference::UnitRef(offset) => {
966                            Operation::Call(convert_unit_offset(offset)?)
967                        }
968                        read::DieReference::DebugInfoRef(offset) => {
969                            Operation::CallRef(convert_debug_info_offset(offset)?)
970                        }
971                    },
972                    read::Operation::TLS => Operation::Simple(constants::DW_OP_form_tls_address),
973                    read::Operation::CallFrameCFA => {
974                        Operation::Simple(constants::DW_OP_call_frame_cfa)
975                    }
976                    read::Operation::Piece {
977                        size_in_bits,
978                        bit_offset: None,
979                    } => Operation::Piece {
980                        size_in_bytes: size_in_bits / 8,
981                    },
982                    read::Operation::Piece {
983                        size_in_bits,
984                        bit_offset: Some(bit_offset),
985                    } => Operation::BitPiece {
986                        size_in_bits,
987                        bit_offset,
988                    },
989                    read::Operation::ImplicitValue { data } => {
990                        Operation::ImplicitValue(data.to_slice()?.into_owned().into())
991                    }
992                    read::Operation::StackValue => Operation::Simple(constants::DW_OP_stack_value),
993                    read::Operation::ImplicitPointer { value, byte_offset } => {
994                        let entry = convert_debug_info_offset(value)?;
995                        Operation::ImplicitPointer { entry, byte_offset }
996                    }
997                    read::Operation::EntryValue { expression } => {
998                        let expression = Expression::from(
999                            read::Expression(expression),
1000                            encoding,
1001                            dwarf,
1002                            unit,
1003                            entry_ids,
1004                            convert_address,
1005                        )?;
1006                        Operation::EntryValue(expression)
1007                    }
1008                    read::Operation::ParameterRef { offset } => {
1009                        let entry = convert_unit_offset(offset)?;
1010                        Operation::ParameterRef(entry)
1011                    }
1012                    read::Operation::Address { address } => {
1013                        let address =
1014                            convert_address(address).ok_or(ConvertError::InvalidAddress)?;
1015                        Operation::Address(address)
1016                    }
1017                    read::Operation::AddressIndex { index } => {
1018                        let dwarf = dwarf.ok_or(ConvertError::UnsupportedOperation)?;
1019                        let unit = unit.ok_or(ConvertError::UnsupportedOperation)?;
1020                        let val = dwarf.address(unit, index)?;
1021                        let address = convert_address(val).ok_or(ConvertError::InvalidAddress)?;
1022                        Operation::Address(address)
1023                    }
1024                    read::Operation::ConstantIndex { index } => {
1025                        let dwarf = dwarf.ok_or(ConvertError::UnsupportedOperation)?;
1026                        let unit = unit.ok_or(ConvertError::UnsupportedOperation)?;
1027                        let val = dwarf.address(unit, index)?;
1028                        Operation::UnsignedConstant(val)
1029                    }
1030                    read::Operation::TypedLiteral { base_type, value } => {
1031                        let entry = convert_unit_offset(base_type)?;
1032                        Operation::ConstantType(entry, value.to_slice()?.into_owned().into())
1033                    }
1034                    read::Operation::Convert { base_type } => {
1035                        if base_type.0 == 0 {
1036                            Operation::Convert(None)
1037                        } else {
1038                            let entry = convert_unit_offset(base_type)?;
1039                            Operation::Convert(Some(entry))
1040                        }
1041                    }
1042                    read::Operation::Reinterpret { base_type } => {
1043                        if base_type.0 == 0 {
1044                            Operation::Reinterpret(None)
1045                        } else {
1046                            let entry = convert_unit_offset(base_type)?;
1047                            Operation::Reinterpret(Some(entry))
1048                        }
1049                    }
1050                    read::Operation::WasmLocal { index } => Operation::WasmLocal(index),
1051                    read::Operation::WasmGlobal { index } => Operation::WasmGlobal(index),
1052                    read::Operation::WasmStack { index } => Operation::WasmStack(index),
1053                };
1054                operations.push(operation);
1055            }
1056            Ok(Expression { operations })
1057        }
1058    }
1059}
1060
1061#[cfg(test)]
1062#[cfg(feature = "read")]
1063mod tests {
1064    use super::*;
1065    use crate::common::{DebugInfoOffset, Format};
1066    use crate::read;
1067    use crate::write::{AttributeValue, Dwarf, EndianVec, LineProgram, Sections, Unit};
1068    use crate::LittleEndian;
1069    use std::collections::HashMap;
1070
1071    #[test]
1072    #[allow(clippy::type_complexity)]
1073    fn test_operation() {
1074        for version in [2, 3, 4, 5] {
1075            for address_size in [4, 8] {
1076                for format in [Format::Dwarf32, Format::Dwarf64] {
1077                    let encoding = Encoding {
1078                        format,
1079                        version,
1080                        address_size,
1081                    };
1082
1083                    let mut dwarf = Dwarf::new();
1084                    let unit_id = dwarf.units.add(Unit::new(encoding, LineProgram::none()));
1085                    let unit = dwarf.units.get_mut(unit_id);
1086
1087                    // Create an entry that can be referenced by the expression.
1088                    let entry_id = unit.add(unit.root(), constants::DW_TAG_base_type);
1089                    let reference = Reference::Entry(unit_id, entry_id);
1090
1091                    // The offsets for the above entry when reading back the expression.
1092                    struct ReadState {
1093                        debug_info_offset: DebugInfoOffset,
1094                        entry_offset: read::UnitOffset,
1095                    }
1096
1097                    let mut reg_expression = Expression::new();
1098                    reg_expression.op_reg(Register(23));
1099
1100                    let operations: &[(
1101                        &dyn Fn(&mut Expression),
1102                        Operation,
1103                        &dyn Fn(&ReadState) -> read::Operation<_>,
1104                    )] = &[
1105                        (
1106                            &|x| x.op_deref(),
1107                            Operation::Deref { space: false },
1108                            &|_| read::Operation::Deref {
1109                                base_type: read::UnitOffset(0),
1110                                size: address_size,
1111                                space: false,
1112                            },
1113                        ),
1114                        (
1115                            &|x| x.op_xderef(),
1116                            Operation::Deref { space: true },
1117                            &|_| read::Operation::Deref {
1118                                base_type: read::UnitOffset(0),
1119                                size: address_size,
1120                                space: true,
1121                            },
1122                        ),
1123                        (
1124                            &|x| x.op_deref_size(2),
1125                            Operation::DerefSize {
1126                                space: false,
1127                                size: 2,
1128                            },
1129                            &|_| read::Operation::Deref {
1130                                base_type: read::UnitOffset(0),
1131                                size: 2,
1132                                space: false,
1133                            },
1134                        ),
1135                        (
1136                            &|x| x.op_xderef_size(2),
1137                            Operation::DerefSize {
1138                                space: true,
1139                                size: 2,
1140                            },
1141                            &|_| read::Operation::Deref {
1142                                base_type: read::UnitOffset(0),
1143                                size: 2,
1144                                space: true,
1145                            },
1146                        ),
1147                        (
1148                            &|x| x.op_deref_type(2, entry_id),
1149                            Operation::DerefType {
1150                                space: false,
1151                                size: 2,
1152                                base: entry_id,
1153                            },
1154                            &|x| read::Operation::Deref {
1155                                base_type: x.entry_offset,
1156                                size: 2,
1157                                space: false,
1158                            },
1159                        ),
1160                        (
1161                            &|x| x.op_xderef_type(2, entry_id),
1162                            Operation::DerefType {
1163                                space: true,
1164                                size: 2,
1165                                base: entry_id,
1166                            },
1167                            &|x| read::Operation::Deref {
1168                                base_type: x.entry_offset,
1169                                size: 2,
1170                                space: true,
1171                            },
1172                        ),
1173                        (
1174                            &|x| x.op(constants::DW_OP_drop),
1175                            Operation::Simple(constants::DW_OP_drop),
1176                            &|_| read::Operation::Drop,
1177                        ),
1178                        (&|x| x.op_pick(0), Operation::Pick(0), &|_| {
1179                            read::Operation::Pick { index: 0 }
1180                        }),
1181                        (&|x| x.op_pick(1), Operation::Pick(1), &|_| {
1182                            read::Operation::Pick { index: 1 }
1183                        }),
1184                        (&|x| x.op_pick(2), Operation::Pick(2), &|_| {
1185                            read::Operation::Pick { index: 2 }
1186                        }),
1187                        (
1188                            &|x| x.op(constants::DW_OP_swap),
1189                            Operation::Simple(constants::DW_OP_swap),
1190                            &|_| read::Operation::Swap,
1191                        ),
1192                        (
1193                            &|x| x.op(constants::DW_OP_rot),
1194                            Operation::Simple(constants::DW_OP_rot),
1195                            &|_| read::Operation::Rot,
1196                        ),
1197                        (
1198                            &|x| x.op(constants::DW_OP_abs),
1199                            Operation::Simple(constants::DW_OP_abs),
1200                            &|_| read::Operation::Abs,
1201                        ),
1202                        (
1203                            &|x| x.op(constants::DW_OP_and),
1204                            Operation::Simple(constants::DW_OP_and),
1205                            &|_| read::Operation::And,
1206                        ),
1207                        (
1208                            &|x| x.op(constants::DW_OP_div),
1209                            Operation::Simple(constants::DW_OP_div),
1210                            &|_| read::Operation::Div,
1211                        ),
1212                        (
1213                            &|x| x.op(constants::DW_OP_minus),
1214                            Operation::Simple(constants::DW_OP_minus),
1215                            &|_| read::Operation::Minus,
1216                        ),
1217                        (
1218                            &|x| x.op(constants::DW_OP_mod),
1219                            Operation::Simple(constants::DW_OP_mod),
1220                            &|_| read::Operation::Mod,
1221                        ),
1222                        (
1223                            &|x| x.op(constants::DW_OP_mul),
1224                            Operation::Simple(constants::DW_OP_mul),
1225                            &|_| read::Operation::Mul,
1226                        ),
1227                        (
1228                            &|x| x.op(constants::DW_OP_neg),
1229                            Operation::Simple(constants::DW_OP_neg),
1230                            &|_| read::Operation::Neg,
1231                        ),
1232                        (
1233                            &|x| x.op(constants::DW_OP_not),
1234                            Operation::Simple(constants::DW_OP_not),
1235                            &|_| read::Operation::Not,
1236                        ),
1237                        (
1238                            &|x| x.op(constants::DW_OP_or),
1239                            Operation::Simple(constants::DW_OP_or),
1240                            &|_| read::Operation::Or,
1241                        ),
1242                        (
1243                            &|x| x.op(constants::DW_OP_plus),
1244                            Operation::Simple(constants::DW_OP_plus),
1245                            &|_| read::Operation::Plus,
1246                        ),
1247                        (
1248                            &|x| x.op_plus_uconst(23),
1249                            Operation::PlusConstant(23),
1250                            &|_| read::Operation::PlusConstant { value: 23 },
1251                        ),
1252                        (
1253                            &|x| x.op(constants::DW_OP_shl),
1254                            Operation::Simple(constants::DW_OP_shl),
1255                            &|_| read::Operation::Shl,
1256                        ),
1257                        (
1258                            &|x| x.op(constants::DW_OP_shr),
1259                            Operation::Simple(constants::DW_OP_shr),
1260                            &|_| read::Operation::Shr,
1261                        ),
1262                        (
1263                            &|x| x.op(constants::DW_OP_shra),
1264                            Operation::Simple(constants::DW_OP_shra),
1265                            &|_| read::Operation::Shra,
1266                        ),
1267                        (
1268                            &|x| x.op(constants::DW_OP_xor),
1269                            Operation::Simple(constants::DW_OP_xor),
1270                            &|_| read::Operation::Xor,
1271                        ),
1272                        (
1273                            &|x| x.op(constants::DW_OP_eq),
1274                            Operation::Simple(constants::DW_OP_eq),
1275                            &|_| read::Operation::Eq,
1276                        ),
1277                        (
1278                            &|x| x.op(constants::DW_OP_ge),
1279                            Operation::Simple(constants::DW_OP_ge),
1280                            &|_| read::Operation::Ge,
1281                        ),
1282                        (
1283                            &|x| x.op(constants::DW_OP_gt),
1284                            Operation::Simple(constants::DW_OP_gt),
1285                            &|_| read::Operation::Gt,
1286                        ),
1287                        (
1288                            &|x| x.op(constants::DW_OP_le),
1289                            Operation::Simple(constants::DW_OP_le),
1290                            &|_| read::Operation::Le,
1291                        ),
1292                        (
1293                            &|x| x.op(constants::DW_OP_lt),
1294                            Operation::Simple(constants::DW_OP_lt),
1295                            &|_| read::Operation::Lt,
1296                        ),
1297                        (
1298                            &|x| x.op(constants::DW_OP_ne),
1299                            Operation::Simple(constants::DW_OP_ne),
1300                            &|_| read::Operation::Ne,
1301                        ),
1302                        (
1303                            &|x| x.op_constu(23),
1304                            Operation::UnsignedConstant(23),
1305                            &|_| read::Operation::UnsignedConstant { value: 23 },
1306                        ),
1307                        (
1308                            &|x| x.op_consts(-23),
1309                            Operation::SignedConstant(-23),
1310                            &|_| read::Operation::SignedConstant { value: -23 },
1311                        ),
1312                        (
1313                            &|x| x.op_reg(Register(23)),
1314                            Operation::Register(Register(23)),
1315                            &|_| read::Operation::Register {
1316                                register: Register(23),
1317                            },
1318                        ),
1319                        (
1320                            &|x| x.op_reg(Register(123)),
1321                            Operation::Register(Register(123)),
1322                            &|_| read::Operation::Register {
1323                                register: Register(123),
1324                            },
1325                        ),
1326                        (
1327                            &|x| x.op_breg(Register(23), 34),
1328                            Operation::RegisterOffset(Register(23), 34),
1329                            &|_| read::Operation::RegisterOffset {
1330                                register: Register(23),
1331                                offset: 34,
1332                                base_type: read::UnitOffset(0),
1333                            },
1334                        ),
1335                        (
1336                            &|x| x.op_breg(Register(123), 34),
1337                            Operation::RegisterOffset(Register(123), 34),
1338                            &|_| read::Operation::RegisterOffset {
1339                                register: Register(123),
1340                                offset: 34,
1341                                base_type: read::UnitOffset(0),
1342                            },
1343                        ),
1344                        (
1345                            &|x| x.op_regval_type(Register(23), entry_id),
1346                            Operation::RegisterType(Register(23), entry_id),
1347                            &|x| read::Operation::RegisterOffset {
1348                                register: Register(23),
1349                                offset: 0,
1350                                base_type: x.entry_offset,
1351                            },
1352                        ),
1353                        (&|x| x.op_fbreg(34), Operation::FrameOffset(34), &|_| {
1354                            read::Operation::FrameOffset { offset: 34 }
1355                        }),
1356                        (
1357                            &|x| x.op(constants::DW_OP_nop),
1358                            Operation::Simple(constants::DW_OP_nop),
1359                            &|_| read::Operation::Nop,
1360                        ),
1361                        (
1362                            &|x| x.op(constants::DW_OP_push_object_address),
1363                            Operation::Simple(constants::DW_OP_push_object_address),
1364                            &|_| read::Operation::PushObjectAddress,
1365                        ),
1366                        (&|x| x.op_call(entry_id), Operation::Call(entry_id), &|x| {
1367                            read::Operation::Call {
1368                                offset: read::DieReference::UnitRef(x.entry_offset),
1369                            }
1370                        }),
1371                        (
1372                            &|x| x.op_call_ref(reference),
1373                            Operation::CallRef(reference),
1374                            &|x| read::Operation::Call {
1375                                offset: read::DieReference::DebugInfoRef(x.debug_info_offset),
1376                            },
1377                        ),
1378                        (
1379                            &|x| x.op(constants::DW_OP_form_tls_address),
1380                            Operation::Simple(constants::DW_OP_form_tls_address),
1381                            &|_| read::Operation::TLS,
1382                        ),
1383                        (
1384                            &|x| x.op(constants::DW_OP_call_frame_cfa),
1385                            Operation::Simple(constants::DW_OP_call_frame_cfa),
1386                            &|_| read::Operation::CallFrameCFA,
1387                        ),
1388                        (
1389                            &|x| x.op_piece(23),
1390                            Operation::Piece { size_in_bytes: 23 },
1391                            &|_| read::Operation::Piece {
1392                                size_in_bits: 23 * 8,
1393                                bit_offset: None,
1394                            },
1395                        ),
1396                        (
1397                            &|x| x.op_bit_piece(23, 34),
1398                            Operation::BitPiece {
1399                                size_in_bits: 23,
1400                                bit_offset: 34,
1401                            },
1402                            &|_| read::Operation::Piece {
1403                                size_in_bits: 23,
1404                                bit_offset: Some(34),
1405                            },
1406                        ),
1407                        (
1408                            &|x| x.op_implicit_value(vec![23].into()),
1409                            Operation::ImplicitValue(vec![23].into()),
1410                            &|_| read::Operation::ImplicitValue {
1411                                data: read::EndianSlice::new(&[23], LittleEndian),
1412                            },
1413                        ),
1414                        (
1415                            &|x| x.op(constants::DW_OP_stack_value),
1416                            Operation::Simple(constants::DW_OP_stack_value),
1417                            &|_| read::Operation::StackValue,
1418                        ),
1419                        (
1420                            &|x| x.op_implicit_pointer(reference, 23),
1421                            Operation::ImplicitPointer {
1422                                entry: reference,
1423                                byte_offset: 23,
1424                            },
1425                            &|x| read::Operation::ImplicitPointer {
1426                                value: x.debug_info_offset,
1427                                byte_offset: 23,
1428                            },
1429                        ),
1430                        (
1431                            &|x| x.op_entry_value(reg_expression.clone()),
1432                            Operation::EntryValue(reg_expression.clone()),
1433                            &|_| read::Operation::EntryValue {
1434                                expression: read::EndianSlice::new(
1435                                    &[constants::DW_OP_reg23.0],
1436                                    LittleEndian,
1437                                ),
1438                            },
1439                        ),
1440                        (
1441                            &|x| x.op_gnu_parameter_ref(entry_id),
1442                            Operation::ParameterRef(entry_id),
1443                            &|x| read::Operation::ParameterRef {
1444                                offset: x.entry_offset,
1445                            },
1446                        ),
1447                        (
1448                            &|x| x.op_addr(Address::Constant(23)),
1449                            Operation::Address(Address::Constant(23)),
1450                            &|_| read::Operation::Address { address: 23 },
1451                        ),
1452                        (
1453                            &|x| x.op_const_type(entry_id, vec![23].into()),
1454                            Operation::ConstantType(entry_id, vec![23].into()),
1455                            &|x| read::Operation::TypedLiteral {
1456                                base_type: x.entry_offset,
1457                                value: read::EndianSlice::new(&[23], LittleEndian),
1458                            },
1459                        ),
1460                        (&|x| x.op_convert(None), Operation::Convert(None), &|_| {
1461                            read::Operation::Convert {
1462                                base_type: read::UnitOffset(0),
1463                            }
1464                        }),
1465                        (
1466                            &|x| x.op_convert(Some(entry_id)),
1467                            Operation::Convert(Some(entry_id)),
1468                            &|x| read::Operation::Convert {
1469                                base_type: x.entry_offset,
1470                            },
1471                        ),
1472                        (
1473                            &|x| x.op_reinterpret(None),
1474                            Operation::Reinterpret(None),
1475                            &|_| read::Operation::Reinterpret {
1476                                base_type: read::UnitOffset(0),
1477                            },
1478                        ),
1479                        (
1480                            &|x| x.op_reinterpret(Some(entry_id)),
1481                            Operation::Reinterpret(Some(entry_id)),
1482                            &|x| read::Operation::Reinterpret {
1483                                base_type: x.entry_offset,
1484                            },
1485                        ),
1486                        (
1487                            &|x| x.op_wasm_local(1000),
1488                            Operation::WasmLocal(1000),
1489                            &|_| read::Operation::WasmLocal { index: 1000 },
1490                        ),
1491                        (
1492                            &|x| x.op_wasm_global(1000),
1493                            Operation::WasmGlobal(1000),
1494                            &|_| read::Operation::WasmGlobal { index: 1000 },
1495                        ),
1496                        (
1497                            &|x| x.op_wasm_stack(1000),
1498                            Operation::WasmStack(1000),
1499                            &|_| read::Operation::WasmStack { index: 1000 },
1500                        ),
1501                    ];
1502
1503                    // Create a single expression containing all operations.
1504                    let mut expression = Expression::new();
1505                    let start_index = expression.next_index();
1506                    for (f, o, _) in operations {
1507                        f(&mut expression);
1508                        assert_eq!(expression.operations.last(), Some(o));
1509                    }
1510
1511                    let bra_index = expression.op_bra();
1512                    let skip_index = expression.op_skip();
1513                    expression.op(constants::DW_OP_nop);
1514                    let end_index = expression.next_index();
1515                    expression.set_target(bra_index, start_index);
1516                    expression.set_target(skip_index, end_index);
1517
1518                    // Create an entry containing the expression.
1519                    let subprogram_id = unit.add(unit.root(), constants::DW_TAG_subprogram);
1520                    let subprogram = unit.get_mut(subprogram_id);
1521                    subprogram.set(
1522                        constants::DW_AT_location,
1523                        AttributeValue::Exprloc(expression),
1524                    );
1525
1526                    // Write the DWARF, then parse it.
1527                    let mut sections = Sections::new(EndianVec::new(LittleEndian));
1528                    dwarf.write(&mut sections).unwrap();
1529
1530                    let read_dwarf = sections.read(LittleEndian);
1531                    let mut read_units = read_dwarf.units();
1532                    let read_unit_header = read_units.next().unwrap().unwrap();
1533                    let read_unit = read_dwarf.unit(read_unit_header).unwrap();
1534                    let mut read_entries = read_unit.entries();
1535                    let (_, read_entry) = read_entries.next_dfs().unwrap().unwrap();
1536                    assert_eq!(read_entry.tag(), constants::DW_TAG_compile_unit);
1537
1538                    // Determine the offset of the entry that can be referenced by the expression.
1539                    let (_, read_entry) = read_entries.next_dfs().unwrap().unwrap();
1540                    assert_eq!(read_entry.tag(), constants::DW_TAG_base_type);
1541                    let read_state = ReadState {
1542                        debug_info_offset: read_entry
1543                            .offset()
1544                            .to_debug_info_offset(&read_unit.header)
1545                            .unwrap(),
1546                        entry_offset: read_entry.offset(),
1547                    };
1548
1549                    // Get the expression.
1550                    let (_, read_entry) = read_entries.next_dfs().unwrap().unwrap();
1551                    assert_eq!(read_entry.tag(), constants::DW_TAG_subprogram);
1552                    let read_attr = read_entry
1553                        .attr_value(constants::DW_AT_location)
1554                        .unwrap()
1555                        .unwrap();
1556                    let read_expression = read_attr.exprloc_value().unwrap();
1557                    let mut read_operations = read_expression.operations(encoding);
1558                    for (_, _, operation) in operations {
1559                        assert_eq!(read_operations.next(), Ok(Some(operation(&read_state))));
1560                    }
1561
1562                    // 4 = DW_OP_skip + i16 + DW_OP_nop
1563                    assert_eq!(
1564                        read_operations.next(),
1565                        Ok(Some(read::Operation::Bra {
1566                            target: -(read_expression.0.len() as i16) + 4
1567                        }))
1568                    );
1569                    // 1 = DW_OP_nop
1570                    assert_eq!(
1571                        read_operations.next(),
1572                        Ok(Some(read::Operation::Skip { target: 1 }))
1573                    );
1574                    assert_eq!(read_operations.next(), Ok(Some(read::Operation::Nop)));
1575                    assert_eq!(read_operations.next(), Ok(None));
1576
1577                    let mut entry_ids = HashMap::new();
1578                    entry_ids.insert(read_state.debug_info_offset.into(), (unit_id, entry_id));
1579                    let convert_expression = Expression::from(
1580                        read_expression,
1581                        encoding,
1582                        Some(&read_dwarf),
1583                        Some(&read_unit),
1584                        Some(&entry_ids),
1585                        &|address| Some(Address::Constant(address)),
1586                    )
1587                    .unwrap();
1588                    let mut convert_operations = convert_expression.operations.iter();
1589                    for (_, operation, _) in operations {
1590                        assert_eq!(convert_operations.next(), Some(operation));
1591                    }
1592                    assert_eq!(
1593                        convert_operations.next(),
1594                        Some(&Operation::Branch(start_index))
1595                    );
1596                    assert_eq!(convert_operations.next(), Some(&Operation::Skip(end_index)));
1597                    assert_eq!(
1598                        convert_operations.next(),
1599                        Some(&Operation::Simple(constants::DW_OP_nop))
1600                    );
1601                }
1602            }
1603        }
1604    }
1605
1606    #[test]
1607    #[allow(clippy::type_complexity)]
1608    fn test_expression_raw() {
1609        for version in [2, 3, 4, 5] {
1610            for address_size in [4, 8] {
1611                for format in [Format::Dwarf32, Format::Dwarf64] {
1612                    let encoding = Encoding {
1613                        format,
1614                        version,
1615                        address_size,
1616                    };
1617
1618                    let mut dwarf = Dwarf::new();
1619                    let unit_id = dwarf.units.add(Unit::new(encoding, LineProgram::none()));
1620                    let unit = dwarf.units.get_mut(unit_id);
1621                    let subprogram_id = unit.add(unit.root(), constants::DW_TAG_subprogram);
1622                    let subprogram = unit.get_mut(subprogram_id);
1623                    let expression = Expression::raw(vec![constants::DW_OP_constu.0, 23]);
1624                    subprogram.set(
1625                        constants::DW_AT_location,
1626                        AttributeValue::Exprloc(expression),
1627                    );
1628
1629                    // Write the DWARF, then parse it.
1630                    let mut sections = Sections::new(EndianVec::new(LittleEndian));
1631                    dwarf.write(&mut sections).unwrap();
1632
1633                    let read_dwarf = sections.read(LittleEndian);
1634                    let mut read_units = read_dwarf.units();
1635                    let read_unit_header = read_units.next().unwrap().unwrap();
1636                    let read_unit = read_dwarf.unit(read_unit_header).unwrap();
1637                    let mut read_entries = read_unit.entries();
1638                    let (_, read_entry) = read_entries.next_dfs().unwrap().unwrap();
1639                    assert_eq!(read_entry.tag(), constants::DW_TAG_compile_unit);
1640                    let (_, read_entry) = read_entries.next_dfs().unwrap().unwrap();
1641                    assert_eq!(read_entry.tag(), constants::DW_TAG_subprogram);
1642                    let read_attr = read_entry
1643                        .attr_value(constants::DW_AT_location)
1644                        .unwrap()
1645                        .unwrap();
1646                    let read_expression = read_attr.exprloc_value().unwrap();
1647                    let mut read_operations = read_expression.operations(encoding);
1648                    assert_eq!(
1649                        read_operations.next(),
1650                        Ok(Some(read::Operation::UnsignedConstant { value: 23 }))
1651                    );
1652                    assert_eq!(read_operations.next(), Ok(None));
1653                }
1654            }
1655        }
1656    }
1657
1658    #[test]
1659    fn test_forward_ref() {
1660        let encoding = Encoding {
1661            format: Format::Dwarf32,
1662            version: 5,
1663            address_size: 8,
1664        };
1665
1666        let mut dwarf = Dwarf::new();
1667        let unit_id = dwarf.units.add(Unit::new(encoding, LineProgram::none()));
1668        let unit = dwarf.units.get_mut(unit_id);
1669
1670        // First, create an entry that will contain the expression.
1671        let subprogram_id = unit.add(unit.root(), constants::DW_TAG_subprogram);
1672
1673        // Now create the entry to be referenced by the expression.
1674        let entry_id = unit.add(unit.root(), constants::DW_TAG_const_type);
1675
1676        // Create an expression containing the reference.
1677        let mut expression = Expression::new();
1678        expression.op_deref_type(2, entry_id);
1679
1680        // Add the expression to the subprogram.
1681        unit.get_mut(subprogram_id).set(
1682            constants::DW_AT_location,
1683            AttributeValue::Exprloc(expression),
1684        );
1685
1686        // Writing the DWARF should fail.
1687        let mut sections = Sections::new(EndianVec::new(LittleEndian));
1688        assert_eq!(
1689            dwarf.write(&mut sections),
1690            Err(Error::UnsupportedExpressionForwardReference)
1691        );
1692    }
1693
1694    #[test]
1695    fn test_missing_unit_ref() {
1696        let encoding = Encoding {
1697            format: Format::Dwarf32,
1698            version: 5,
1699            address_size: 8,
1700        };
1701
1702        let mut dwarf = Dwarf::new();
1703        let unit_id = dwarf.units.add(Unit::new(encoding, LineProgram::none()));
1704        let unit = dwarf.units.get_mut(unit_id);
1705
1706        // Create the entry to be referenced by the expression.
1707        let entry_id = unit.add(unit.root(), constants::DW_TAG_const_type);
1708        // And delete it so that it is not available when writing the expression.
1709        unit.get_mut(unit.root()).delete_child(entry_id);
1710
1711        // Create an expression containing the reference.
1712        let mut expression = Expression::new();
1713        expression.op_deref_type(2, entry_id);
1714
1715        // Create an entry containing the expression.
1716        let subprogram_id = unit.add(unit.root(), constants::DW_TAG_subprogram);
1717        unit.get_mut(subprogram_id).set(
1718            constants::DW_AT_location,
1719            AttributeValue::Exprloc(expression),
1720        );
1721
1722        // Writing the DWARF should fail.
1723        let mut sections = Sections::new(EndianVec::new(LittleEndian));
1724        assert_eq!(
1725            dwarf.write(&mut sections),
1726            Err(Error::UnsupportedExpressionForwardReference)
1727        );
1728    }
1729
1730    #[test]
1731    fn test_missing_debuginfo_ref() {
1732        let encoding = Encoding {
1733            format: Format::Dwarf32,
1734            version: 5,
1735            address_size: 8,
1736        };
1737
1738        let mut dwarf = Dwarf::new();
1739        let unit_id = dwarf.units.add(Unit::new(encoding, LineProgram::none()));
1740        let unit = dwarf.units.get_mut(unit_id);
1741
1742        // Create the entry to be referenced by the expression.
1743        let entry_id = unit.add(unit.root(), constants::DW_TAG_const_type);
1744        // And delete it so that it is not available when writing the expression.
1745        unit.get_mut(unit.root()).delete_child(entry_id);
1746
1747        // Create an expression containing the reference.
1748        let mut expression = Expression::new();
1749        expression.op_call_ref(Reference::Entry(unit_id, entry_id));
1750
1751        // Create an entry containing the expression.
1752        let subprogram_id = unit.add(unit.root(), constants::DW_TAG_subprogram);
1753        unit.get_mut(subprogram_id).set(
1754            constants::DW_AT_location,
1755            AttributeValue::Exprloc(expression),
1756        );
1757
1758        // Writing the DWARF should fail.
1759        let mut sections = Sections::new(EndianVec::new(LittleEndian));
1760        assert_eq!(dwarf.write(&mut sections), Err(Error::InvalidReference));
1761    }
1762}