Skip to main content

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