Coverage Report

Created: 2026-01-17 06:11

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