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