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 encoding.format.word_size() as usize + sleb128_size(byte_offset)
570 }
571 Operation::Piece { size_in_bytes } => uleb128_size(size_in_bytes),
572 Operation::BitPiece {
573 size_in_bits,
574 bit_offset,
575 } => uleb128_size(size_in_bits) + uleb128_size(bit_offset),
576 Operation::ParameterRef(_) => 4,
577 Operation::WasmLocal(index)
578 | Operation::WasmGlobal(index)
579 | Operation::WasmStack(index) => 1 + uleb128_size(index.into()),
580 }
581 }
582
583 pub(crate) fn write<W: Writer>(
584 &self,
585 w: &mut W,
586 refs: Option<&mut Vec<DebugInfoReference>>,
587 encoding: Encoding,
588 unit_offsets: Option<&UnitOffsets>,
589 offsets: &[usize],
590 ) -> Result<()> {
591 let entry_offset = |entry| match unit_offsets {
592 Some(offsets) => {
593 let offset = offsets.unit_offset(entry);
594 if offset == 0 {
595 Err(Error::UnsupportedExpressionForwardReference)
596 } else {
597 Ok(offset)
598 }
599 }
600 None => Err(Error::UnsupportedCfiExpressionReference),
601 };
602 match *self {
603 Operation::Raw(ref bytecode) => w.write(bytecode)?,
604 Operation::Simple(opcode) => w.write_u8(opcode.0)?,
605 Operation::Address(address) => {
606 w.write_u8(constants::DW_OP_addr.0)?;
607 w.write_address(address, encoding.address_size)?;
608 }
609 Operation::UnsignedConstant(value) => {
610 if value < 32 {
611 w.write_u8(constants::DW_OP_lit0.0 + value as u8)?;
612 } else {
613 w.write_u8(constants::DW_OP_constu.0)?;
614 w.write_uleb128(value)?;
615 }
616 }
617 Operation::SignedConstant(value) => {
618 w.write_u8(constants::DW_OP_consts.0)?;
619 w.write_sleb128(value)?;
620 }
621 Operation::ConstantType(base, ref value) => {
622 if encoding.version >= 5 {
623 w.write_u8(constants::DW_OP_const_type.0)?;
624 } else {
625 w.write_u8(constants::DW_OP_GNU_const_type.0)?;
626 }
627 w.write_uleb128(entry_offset(base)?)?;
628 w.write_udata(value.len() as u64, 1)?;
629 w.write(value)?;
630 }
631 Operation::FrameOffset(offset) => {
632 w.write_u8(constants::DW_OP_fbreg.0)?;
633 w.write_sleb128(offset)?;
634 }
635 Operation::RegisterOffset(register, offset) => {
636 if register.0 < 32 {
637 w.write_u8(constants::DW_OP_breg0.0 + register.0 as u8)?;
638 } else {
639 w.write_u8(constants::DW_OP_bregx.0)?;
640 w.write_uleb128(register.0.into())?;
641 }
642 w.write_sleb128(offset)?;
643 }
644 Operation::RegisterType(register, base) => {
645 if encoding.version >= 5 {
646 w.write_u8(constants::DW_OP_regval_type.0)?;
647 } else {
648 w.write_u8(constants::DW_OP_GNU_regval_type.0)?;
649 }
650 w.write_uleb128(register.0.into())?;
651 w.write_uleb128(entry_offset(base)?)?;
652 }
653 Operation::Pick(index) => match index {
654 0 => w.write_u8(constants::DW_OP_dup.0)?,
655 1 => w.write_u8(constants::DW_OP_over.0)?,
656 _ => {
657 w.write_u8(constants::DW_OP_pick.0)?;
658 w.write_u8(index)?;
659 }
660 },
661 Operation::Deref { space } => {
662 if space {
663 w.write_u8(constants::DW_OP_xderef.0)?;
664 } else {
665 w.write_u8(constants::DW_OP_deref.0)?;
666 }
667 }
668 Operation::DerefSize { space, size } => {
669 if space {
670 w.write_u8(constants::DW_OP_xderef_size.0)?;
671 } else {
672 w.write_u8(constants::DW_OP_deref_size.0)?;
673 }
674 w.write_u8(size)?;
675 }
676 Operation::DerefType { space, size, base } => {
677 if space {
678 w.write_u8(constants::DW_OP_xderef_type.0)?;
679 } else {
680 if encoding.version >= 5 {
681 w.write_u8(constants::DW_OP_deref_type.0)?;
682 } else {
683 w.write_u8(constants::DW_OP_GNU_deref_type.0)?;
684 }
685 }
686 w.write_u8(size)?;
687 w.write_uleb128(entry_offset(base)?)?;
688 }
689 Operation::PlusConstant(value) => {
690 w.write_u8(constants::DW_OP_plus_uconst.0)?;
691 w.write_uleb128(value)?;
692 }
693 Operation::Skip(target) => {
694 w.write_u8(constants::DW_OP_skip.0)?;
695 let offset = offsets[target] as i64 - (w.len() as i64 + 2);
696 w.write_sdata(offset, 2)?;
697 }
698 Operation::Branch(target) => {
699 w.write_u8(constants::DW_OP_bra.0)?;
700 let offset = offsets[target] as i64 - (w.len() as i64 + 2);
701 w.write_sdata(offset, 2)?;
702 }
703 Operation::Call(entry) => {
704 w.write_u8(constants::DW_OP_call4.0)?;
705 // TODO: this probably won't work in practice, because we may
706 // only know the offsets of base type DIEs at this point.
707 w.write_udata(entry_offset(entry)?, 4)?;
708 }
709 Operation::CallRef(entry) => {
710 w.write_u8(constants::DW_OP_call_ref.0)?;
711 let size = encoding.format.word_size();
712 match entry {
713 Reference::Symbol(symbol) => w.write_reference(symbol, size)?,
714 Reference::Entry(unit, entry) => {
715 let refs = refs.ok_or(Error::InvalidReference)?;
716 refs.push(DebugInfoReference {
717 offset: w.len(),
718 unit,
719 entry,
720 size,
721 });
722 w.write_udata(0, size)?;
723 }
724 }
725 }
726 Operation::Convert(base) => {
727 if encoding.version >= 5 {
728 w.write_u8(constants::DW_OP_convert.0)?;
729 } else {
730 w.write_u8(constants::DW_OP_GNU_convert.0)?;
731 }
732 match base {
733 Some(base) => w.write_uleb128(entry_offset(base)?)?,
734 None => w.write_u8(0)?,
735 }
736 }
737 Operation::Reinterpret(base) => {
738 if encoding.version >= 5 {
739 w.write_u8(constants::DW_OP_reinterpret.0)?;
740 } else {
741 w.write_u8(constants::DW_OP_GNU_reinterpret.0)?;
742 }
743 match base {
744 Some(base) => w.write_uleb128(entry_offset(base)?)?,
745 None => w.write_u8(0)?,
746 }
747 }
748 Operation::EntryValue(ref expression) => {
749 if encoding.version >= 5 {
750 w.write_u8(constants::DW_OP_entry_value.0)?;
751 } else {
752 w.write_u8(constants::DW_OP_GNU_entry_value.0)?;
753 }
754 let length = expression.size(encoding, unit_offsets);
755 w.write_uleb128(length as u64)?;
756 expression.write(w, refs, encoding, unit_offsets)?;
757 }
758 Operation::Register(register) => {
759 if register.0 < 32 {
760 w.write_u8(constants::DW_OP_reg0.0 + register.0 as u8)?;
761 } else {
762 w.write_u8(constants::DW_OP_regx.0)?;
763 w.write_uleb128(register.0.into())?;
764 }
765 }
766 Operation::ImplicitValue(ref data) => {
767 w.write_u8(constants::DW_OP_implicit_value.0)?;
768 w.write_uleb128(data.len() as u64)?;
769 w.write(data)?;
770 }
771 Operation::ImplicitPointer { entry, byte_offset } => {
772 if encoding.version >= 5 {
773 w.write_u8(constants::DW_OP_implicit_pointer.0)?;
774 } else {
775 w.write_u8(constants::DW_OP_GNU_implicit_pointer.0)?;
776 }
777 let size = if encoding.version == 2 {
778 encoding.address_size
779 } else {
780 encoding.format.word_size()
781 };
782 match entry {
783 Reference::Symbol(symbol) => {
784 w.write_reference(symbol, size)?;
785 }
786 Reference::Entry(unit, entry) => {
787 let refs = refs.ok_or(Error::InvalidReference)?;
788 refs.push(DebugInfoReference {
789 offset: w.len(),
790 unit,
791 entry,
792 size,
793 });
794 w.write_udata(0, size)?;
795 }
796 }
797 w.write_sleb128(byte_offset)?;
798 }
799 Operation::Piece { size_in_bytes } => {
800 w.write_u8(constants::DW_OP_piece.0)?;
801 w.write_uleb128(size_in_bytes)?;
802 }
803 Operation::BitPiece {
804 size_in_bits,
805 bit_offset,
806 } => {
807 w.write_u8(constants::DW_OP_bit_piece.0)?;
808 w.write_uleb128(size_in_bits)?;
809 w.write_uleb128(bit_offset)?;
810 }
811 Operation::ParameterRef(entry) => {
812 w.write_u8(constants::DW_OP_GNU_parameter_ref.0)?;
813 w.write_udata(entry_offset(entry)?, 4)?;
814 }
815 Operation::WasmLocal(index) => {
816 w.write(&[constants::DW_OP_WASM_location.0, 0])?;
817 w.write_uleb128(index.into())?;
818 }
819 Operation::WasmGlobal(index) => {
820 w.write(&[constants::DW_OP_WASM_location.0, 1])?;
821 w.write_uleb128(index.into())?;
822 }
823 Operation::WasmStack(index) => {
824 w.write(&[constants::DW_OP_WASM_location.0, 2])?;
825 w.write_uleb128(index.into())?;
826 }
827 }
828 Ok(())
829 }
830}
831
832#[cfg(feature = "read")]
833pub(crate) mod convert {
834 use super::*;
835 use crate::common::UnitSectionOffset;
836 use crate::read::{self, Reader};
837 use crate::write::{ConvertError, ConvertResult, UnitEntryId, UnitId};
838 use std::collections::HashMap;
839
840 impl Expression {
841 /// Create an expression from the input expression.
842 pub fn from<R: Reader<Offset = usize>>(
843 from_expression: read::Expression<R>,
844 encoding: Encoding,
845 dwarf: Option<&read::Dwarf<R>>,
846 unit: Option<&read::Unit<R>>,
847 entry_ids: Option<&HashMap<UnitSectionOffset, (UnitId, UnitEntryId)>>,
848 convert_address: &dyn Fn(u64) -> Option<Address>,
849 ) -> ConvertResult<Expression> {
850 let convert_unit_offset = |offset: read::UnitOffset| -> ConvertResult<_> {
851 let entry_ids = entry_ids.ok_or(ConvertError::UnsupportedOperation)?;
852 let unit = unit.ok_or(ConvertError::UnsupportedOperation)?;
853 let id = entry_ids
854 .get(&offset.to_unit_section_offset(unit))
855 .ok_or(ConvertError::InvalidUnitRef)?;
856 Ok(id.1)
857 };
858 let convert_debug_info_offset = |offset| -> ConvertResult<_> {
859 // TODO: support relocations
860 let entry_ids = entry_ids.ok_or(ConvertError::UnsupportedOperation)?;
861 let id = entry_ids
862 .get(&UnitSectionOffset::DebugInfoOffset(offset))
863 .ok_or(ConvertError::InvalidDebugInfoRef)?;
864 Ok(Reference::Entry(id.0, id.1))
865 };
866
867 // Calculate offsets for use in branch/skip operations.
868 let mut offsets = Vec::new();
869 let mut offset = 0;
870 let mut from_operations = from_expression.clone().operations(encoding);
871 while from_operations.next()?.is_some() {
872 offsets.push(offset);
873 offset = from_operations.offset_from(&from_expression);
874 }
875 offsets.push(from_expression.0.len());
876
877 let mut from_operations = from_expression.clone().operations(encoding);
878 let mut operations = Vec::new();
879 while let Some(from_operation) = from_operations.next()? {
880 let operation = match from_operation {
881 read::Operation::Deref {
882 base_type,
883 size,
884 space,
885 } => {
886 if base_type.0 != 0 {
887 let base = convert_unit_offset(base_type)?;
888 Operation::DerefType { space, size, base }
889 } else if size != encoding.address_size {
890 Operation::DerefSize { space, size }
891 } else {
892 Operation::Deref { space }
893 }
894 }
895 read::Operation::Drop => Operation::Simple(constants::DW_OP_drop),
896 read::Operation::Pick { index } => Operation::Pick(index),
897 read::Operation::Swap => Operation::Simple(constants::DW_OP_swap),
898 read::Operation::Rot => Operation::Simple(constants::DW_OP_rot),
899 read::Operation::Abs => Operation::Simple(constants::DW_OP_abs),
900 read::Operation::And => Operation::Simple(constants::DW_OP_and),
901 read::Operation::Div => Operation::Simple(constants::DW_OP_div),
902 read::Operation::Minus => Operation::Simple(constants::DW_OP_minus),
903 read::Operation::Mod => Operation::Simple(constants::DW_OP_mod),
904 read::Operation::Mul => Operation::Simple(constants::DW_OP_mul),
905 read::Operation::Neg => Operation::Simple(constants::DW_OP_neg),
906 read::Operation::Not => Operation::Simple(constants::DW_OP_not),
907 read::Operation::Or => Operation::Simple(constants::DW_OP_or),
908 read::Operation::Plus => Operation::Simple(constants::DW_OP_plus),
909 read::Operation::PlusConstant { value } => Operation::PlusConstant(value),
910 read::Operation::Shl => Operation::Simple(constants::DW_OP_shl),
911 read::Operation::Shr => Operation::Simple(constants::DW_OP_shr),
912 read::Operation::Shra => Operation::Simple(constants::DW_OP_shra),
913 read::Operation::Xor => Operation::Simple(constants::DW_OP_xor),
914 read::Operation::Eq => Operation::Simple(constants::DW_OP_eq),
915 read::Operation::Ge => Operation::Simple(constants::DW_OP_ge),
916 read::Operation::Gt => Operation::Simple(constants::DW_OP_gt),
917 read::Operation::Le => Operation::Simple(constants::DW_OP_le),
918 read::Operation::Lt => Operation::Simple(constants::DW_OP_lt),
919 read::Operation::Ne => Operation::Simple(constants::DW_OP_ne),
920 read::Operation::Bra { target } => {
921 let offset = from_operations
922 .offset_from(&from_expression)
923 .wrapping_add(i64::from(target) as usize);
924 let index = offsets
925 .binary_search(&offset)
926 .map_err(|_| ConvertError::InvalidBranchTarget)?;
927 Operation::Branch(index)
928 }
929 read::Operation::Skip { target } => {
930 let offset = from_operations
931 .offset_from(&from_expression)
932 .wrapping_add(i64::from(target) as usize);
933 let index = offsets
934 .binary_search(&offset)
935 .map_err(|_| ConvertError::InvalidBranchTarget)?;
936 Operation::Skip(index)
937 }
938 read::Operation::UnsignedConstant { value } => {
939 Operation::UnsignedConstant(value)
940 }
941 read::Operation::SignedConstant { value } => Operation::SignedConstant(value),
942 read::Operation::Register { register } => Operation::Register(register),
943 read::Operation::RegisterOffset {
944 register,
945 offset,
946 base_type,
947 } => {
948 if base_type.0 != 0 {
949 Operation::RegisterType(register, convert_unit_offset(base_type)?)
950 } else {
951 Operation::RegisterOffset(register, offset)
952 }
953 }
954 read::Operation::FrameOffset { offset } => Operation::FrameOffset(offset),
955 read::Operation::Nop => Operation::Simple(constants::DW_OP_nop),
956 read::Operation::PushObjectAddress => {
957 Operation::Simple(constants::DW_OP_push_object_address)
958 }
959 read::Operation::Call { offset } => match offset {
960 read::DieReference::UnitRef(offset) => {
961 Operation::Call(convert_unit_offset(offset)?)
962 }
963 read::DieReference::DebugInfoRef(offset) => {
964 Operation::CallRef(convert_debug_info_offset(offset)?)
965 }
966 },
967 read::Operation::TLS => Operation::Simple(constants::DW_OP_form_tls_address),
968 read::Operation::CallFrameCFA => {
969 Operation::Simple(constants::DW_OP_call_frame_cfa)
970 }
971 read::Operation::Piece {
972 size_in_bits,
973 bit_offset: None,
974 } => Operation::Piece {
975 size_in_bytes: size_in_bits / 8,
976 },
977 read::Operation::Piece {
978 size_in_bits,
979 bit_offset: Some(bit_offset),
980 } => Operation::BitPiece {
981 size_in_bits,
982 bit_offset,
983 },
984 read::Operation::ImplicitValue { data } => {
985 Operation::ImplicitValue(data.to_slice()?.into_owned().into())
986 }
987 read::Operation::StackValue => Operation::Simple(constants::DW_OP_stack_value),
988 read::Operation::ImplicitPointer { value, byte_offset } => {
989 let entry = convert_debug_info_offset(value)?;
990 Operation::ImplicitPointer { entry, byte_offset }
991 }
992 read::Operation::EntryValue { expression } => {
993 let expression = Expression::from(
994 read::Expression(expression),
995 encoding,
996 dwarf,
997 unit,
998 entry_ids,
999 convert_address,
1000 )?;
1001 Operation::EntryValue(expression)
1002 }
1003 read::Operation::ParameterRef { offset } => {
1004 let entry = convert_unit_offset(offset)?;
1005 Operation::ParameterRef(entry)
1006 }
1007 read::Operation::Address { address } => {
1008 let address =
1009 convert_address(address).ok_or(ConvertError::InvalidAddress)?;
1010 Operation::Address(address)
1011 }
1012 read::Operation::AddressIndex { index } => {
1013 let dwarf = dwarf.ok_or(ConvertError::UnsupportedOperation)?;
1014 let unit = unit.ok_or(ConvertError::UnsupportedOperation)?;
1015 let val = dwarf.address(unit, index)?;
1016 let address = convert_address(val).ok_or(ConvertError::InvalidAddress)?;
1017 Operation::Address(address)
1018 }
1019 read::Operation::ConstantIndex { index } => {
1020 let dwarf = dwarf.ok_or(ConvertError::UnsupportedOperation)?;
1021 let unit = unit.ok_or(ConvertError::UnsupportedOperation)?;
1022 let val = dwarf.address(unit, index)?;
1023 Operation::UnsignedConstant(val)
1024 }
1025 read::Operation::TypedLiteral { base_type, value } => {
1026 let entry = convert_unit_offset(base_type)?;
1027 Operation::ConstantType(entry, value.to_slice()?.into_owned().into())
1028 }
1029 read::Operation::Convert { base_type } => {
1030 if base_type.0 == 0 {
1031 Operation::Convert(None)
1032 } else {
1033 let entry = convert_unit_offset(base_type)?;
1034 Operation::Convert(Some(entry))
1035 }
1036 }
1037 read::Operation::Reinterpret { base_type } => {
1038 if base_type.0 == 0 {
1039 Operation::Reinterpret(None)
1040 } else {
1041 let entry = convert_unit_offset(base_type)?;
1042 Operation::Reinterpret(Some(entry))
1043 }
1044 }
1045 read::Operation::WasmLocal { index } => Operation::WasmLocal(index),
1046 read::Operation::WasmGlobal { index } => Operation::WasmGlobal(index),
1047 read::Operation::WasmStack { index } => Operation::WasmStack(index),
1048 };
1049 operations.push(operation);
1050 }
1051 Ok(Expression { operations })
1052 }
1053 }
1054}
1055
1056#[cfg(test)]
1057#[cfg(feature = "read")]
1058mod tests {
1059 use super::*;
1060 use crate::common::{
1061 DebugAbbrevOffset, DebugAddrBase, DebugInfoOffset, DebugLocListsBase, DebugRngListsBase,
1062 DebugStrOffsetsBase, Format, SectionId,
1063 };
1064 use crate::read;
1065 use crate::write::{
1066 DebugLineStrOffsets, DebugStrOffsets, EndianVec, LineProgram, Sections, Unit, UnitTable,
1067 };
1068 use crate::LittleEndian;
1069 use std::collections::HashMap;
1070 use std::sync::Arc;
1071
1072 #[test]
1073 fn test_operation() {
1074 for &version in &[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 units = UnitTable::default();
1084 let unit_id = units.add(Unit::new(encoding, LineProgram::none()));
1085 let unit = units.get_mut(unit_id);
1086 let entry_id = unit.add(unit.root(), constants::DW_TAG_base_type);
1087 let reference = Reference::Entry(unit_id, entry_id);
1088
1089 let mut sections = Sections::new(EndianVec::new(LittleEndian));
1090 let debug_line_str_offsets = DebugLineStrOffsets::none();
1091 let debug_str_offsets = DebugStrOffsets::none();
1092 let debug_info_offsets = units
1093 .write(&mut sections, &debug_line_str_offsets, &debug_str_offsets)
1094 .unwrap();
1095 let unit_offsets = debug_info_offsets.unit_offsets(unit_id);
1096 let debug_info_offset = unit_offsets.debug_info_offset(entry_id);
1097 let entry_offset =
1098 read::UnitOffset(unit_offsets.unit_offset(entry_id) as usize);
1099
1100 let mut reg_expression = Expression::new();
1101 reg_expression.op_reg(Register(23));
1102
1103 let operations: &[(&dyn Fn(&mut Expression), Operation, 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 read::Operation::Deref {
1155 base_type: 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 read::Operation::Deref {
1168 base_type: 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 (
1179 &|x| x.op_pick(0),
1180 Operation::Pick(0),
1181 read::Operation::Pick { index: 0 },
1182 ),
1183 (
1184 &|x| x.op_pick(1),
1185 Operation::Pick(1),
1186 read::Operation::Pick { index: 1 },
1187 ),
1188 (
1189 &|x| x.op_pick(2),
1190 Operation::Pick(2),
1191 read::Operation::Pick { index: 2 },
1192 ),
1193 (
1194 &|x| x.op(constants::DW_OP_swap),
1195 Operation::Simple(constants::DW_OP_swap),
1196 read::Operation::Swap,
1197 ),
1198 (
1199 &|x| x.op(constants::DW_OP_rot),
1200 Operation::Simple(constants::DW_OP_rot),
1201 read::Operation::Rot,
1202 ),
1203 (
1204 &|x| x.op(constants::DW_OP_abs),
1205 Operation::Simple(constants::DW_OP_abs),
1206 read::Operation::Abs,
1207 ),
1208 (
1209 &|x| x.op(constants::DW_OP_and),
1210 Operation::Simple(constants::DW_OP_and),
1211 read::Operation::And,
1212 ),
1213 (
1214 &|x| x.op(constants::DW_OP_div),
1215 Operation::Simple(constants::DW_OP_div),
1216 read::Operation::Div,
1217 ),
1218 (
1219 &|x| x.op(constants::DW_OP_minus),
1220 Operation::Simple(constants::DW_OP_minus),
1221 read::Operation::Minus,
1222 ),
1223 (
1224 &|x| x.op(constants::DW_OP_mod),
1225 Operation::Simple(constants::DW_OP_mod),
1226 read::Operation::Mod,
1227 ),
1228 (
1229 &|x| x.op(constants::DW_OP_mul),
1230 Operation::Simple(constants::DW_OP_mul),
1231 read::Operation::Mul,
1232 ),
1233 (
1234 &|x| x.op(constants::DW_OP_neg),
1235 Operation::Simple(constants::DW_OP_neg),
1236 read::Operation::Neg,
1237 ),
1238 (
1239 &|x| x.op(constants::DW_OP_not),
1240 Operation::Simple(constants::DW_OP_not),
1241 read::Operation::Not,
1242 ),
1243 (
1244 &|x| x.op(constants::DW_OP_or),
1245 Operation::Simple(constants::DW_OP_or),
1246 read::Operation::Or,
1247 ),
1248 (
1249 &|x| x.op(constants::DW_OP_plus),
1250 Operation::Simple(constants::DW_OP_plus),
1251 read::Operation::Plus,
1252 ),
1253 (
1254 &|x| x.op_plus_uconst(23),
1255 Operation::PlusConstant(23),
1256 read::Operation::PlusConstant { value: 23 },
1257 ),
1258 (
1259 &|x| x.op(constants::DW_OP_shl),
1260 Operation::Simple(constants::DW_OP_shl),
1261 read::Operation::Shl,
1262 ),
1263 (
1264 &|x| x.op(constants::DW_OP_shr),
1265 Operation::Simple(constants::DW_OP_shr),
1266 read::Operation::Shr,
1267 ),
1268 (
1269 &|x| x.op(constants::DW_OP_shra),
1270 Operation::Simple(constants::DW_OP_shra),
1271 read::Operation::Shra,
1272 ),
1273 (
1274 &|x| x.op(constants::DW_OP_xor),
1275 Operation::Simple(constants::DW_OP_xor),
1276 read::Operation::Xor,
1277 ),
1278 (
1279 &|x| x.op(constants::DW_OP_eq),
1280 Operation::Simple(constants::DW_OP_eq),
1281 read::Operation::Eq,
1282 ),
1283 (
1284 &|x| x.op(constants::DW_OP_ge),
1285 Operation::Simple(constants::DW_OP_ge),
1286 read::Operation::Ge,
1287 ),
1288 (
1289 &|x| x.op(constants::DW_OP_gt),
1290 Operation::Simple(constants::DW_OP_gt),
1291 read::Operation::Gt,
1292 ),
1293 (
1294 &|x| x.op(constants::DW_OP_le),
1295 Operation::Simple(constants::DW_OP_le),
1296 read::Operation::Le,
1297 ),
1298 (
1299 &|x| x.op(constants::DW_OP_lt),
1300 Operation::Simple(constants::DW_OP_lt),
1301 read::Operation::Lt,
1302 ),
1303 (
1304 &|x| x.op(constants::DW_OP_ne),
1305 Operation::Simple(constants::DW_OP_ne),
1306 read::Operation::Ne,
1307 ),
1308 (
1309 &|x| x.op_constu(23),
1310 Operation::UnsignedConstant(23),
1311 read::Operation::UnsignedConstant { value: 23 },
1312 ),
1313 (
1314 &|x| x.op_consts(-23),
1315 Operation::SignedConstant(-23),
1316 read::Operation::SignedConstant { value: -23 },
1317 ),
1318 (
1319 &|x| x.op_reg(Register(23)),
1320 Operation::Register(Register(23)),
1321 read::Operation::Register {
1322 register: Register(23),
1323 },
1324 ),
1325 (
1326 &|x| x.op_reg(Register(123)),
1327 Operation::Register(Register(123)),
1328 read::Operation::Register {
1329 register: Register(123),
1330 },
1331 ),
1332 (
1333 &|x| x.op_breg(Register(23), 34),
1334 Operation::RegisterOffset(Register(23), 34),
1335 read::Operation::RegisterOffset {
1336 register: Register(23),
1337 offset: 34,
1338 base_type: read::UnitOffset(0),
1339 },
1340 ),
1341 (
1342 &|x| x.op_breg(Register(123), 34),
1343 Operation::RegisterOffset(Register(123), 34),
1344 read::Operation::RegisterOffset {
1345 register: Register(123),
1346 offset: 34,
1347 base_type: read::UnitOffset(0),
1348 },
1349 ),
1350 (
1351 &|x| x.op_regval_type(Register(23), entry_id),
1352 Operation::RegisterType(Register(23), entry_id),
1353 read::Operation::RegisterOffset {
1354 register: Register(23),
1355 offset: 0,
1356 base_type: entry_offset,
1357 },
1358 ),
1359 (
1360 &|x| x.op_fbreg(34),
1361 Operation::FrameOffset(34),
1362 read::Operation::FrameOffset { offset: 34 },
1363 ),
1364 (
1365 &|x| x.op(constants::DW_OP_nop),
1366 Operation::Simple(constants::DW_OP_nop),
1367 read::Operation::Nop,
1368 ),
1369 (
1370 &|x| x.op(constants::DW_OP_push_object_address),
1371 Operation::Simple(constants::DW_OP_push_object_address),
1372 read::Operation::PushObjectAddress,
1373 ),
1374 (
1375 &|x| x.op_call(entry_id),
1376 Operation::Call(entry_id),
1377 read::Operation::Call {
1378 offset: read::DieReference::UnitRef(entry_offset),
1379 },
1380 ),
1381 (
1382 &|x| x.op_call_ref(reference),
1383 Operation::CallRef(reference),
1384 read::Operation::Call {
1385 offset: read::DieReference::DebugInfoRef(debug_info_offset),
1386 },
1387 ),
1388 (
1389 &|x| x.op(constants::DW_OP_form_tls_address),
1390 Operation::Simple(constants::DW_OP_form_tls_address),
1391 read::Operation::TLS,
1392 ),
1393 (
1394 &|x| x.op(constants::DW_OP_call_frame_cfa),
1395 Operation::Simple(constants::DW_OP_call_frame_cfa),
1396 read::Operation::CallFrameCFA,
1397 ),
1398 (
1399 &|x| x.op_piece(23),
1400 Operation::Piece { size_in_bytes: 23 },
1401 read::Operation::Piece {
1402 size_in_bits: 23 * 8,
1403 bit_offset: None,
1404 },
1405 ),
1406 (
1407 &|x| x.op_bit_piece(23, 34),
1408 Operation::BitPiece {
1409 size_in_bits: 23,
1410 bit_offset: 34,
1411 },
1412 read::Operation::Piece {
1413 size_in_bits: 23,
1414 bit_offset: Some(34),
1415 },
1416 ),
1417 (
1418 &|x| x.op_implicit_value(vec![23].into()),
1419 Operation::ImplicitValue(vec![23].into()),
1420 read::Operation::ImplicitValue {
1421 data: read::EndianSlice::new(&[23], LittleEndian),
1422 },
1423 ),
1424 (
1425 &|x| x.op(constants::DW_OP_stack_value),
1426 Operation::Simple(constants::DW_OP_stack_value),
1427 read::Operation::StackValue,
1428 ),
1429 (
1430 &|x| x.op_implicit_pointer(reference, 23),
1431 Operation::ImplicitPointer {
1432 entry: reference,
1433 byte_offset: 23,
1434 },
1435 read::Operation::ImplicitPointer {
1436 value: debug_info_offset,
1437 byte_offset: 23,
1438 },
1439 ),
1440 (
1441 &|x| x.op_entry_value(reg_expression.clone()),
1442 Operation::EntryValue(reg_expression.clone()),
1443 read::Operation::EntryValue {
1444 expression: read::EndianSlice::new(
1445 &[constants::DW_OP_reg23.0],
1446 LittleEndian,
1447 ),
1448 },
1449 ),
1450 (
1451 &|x| x.op_gnu_parameter_ref(entry_id),
1452 Operation::ParameterRef(entry_id),
1453 read::Operation::ParameterRef {
1454 offset: entry_offset,
1455 },
1456 ),
1457 (
1458 &|x| x.op_addr(Address::Constant(23)),
1459 Operation::Address(Address::Constant(23)),
1460 read::Operation::Address { address: 23 },
1461 ),
1462 (
1463 &|x| x.op_const_type(entry_id, vec![23].into()),
1464 Operation::ConstantType(entry_id, vec![23].into()),
1465 read::Operation::TypedLiteral {
1466 base_type: entry_offset,
1467 value: read::EndianSlice::new(&[23], LittleEndian),
1468 },
1469 ),
1470 (
1471 &|x| x.op_convert(None),
1472 Operation::Convert(None),
1473 read::Operation::Convert {
1474 base_type: read::UnitOffset(0),
1475 },
1476 ),
1477 (
1478 &|x| x.op_convert(Some(entry_id)),
1479 Operation::Convert(Some(entry_id)),
1480 read::Operation::Convert {
1481 base_type: entry_offset,
1482 },
1483 ),
1484 (
1485 &|x| x.op_reinterpret(None),
1486 Operation::Reinterpret(None),
1487 read::Operation::Reinterpret {
1488 base_type: read::UnitOffset(0),
1489 },
1490 ),
1491 (
1492 &|x| x.op_reinterpret(Some(entry_id)),
1493 Operation::Reinterpret(Some(entry_id)),
1494 read::Operation::Reinterpret {
1495 base_type: entry_offset,
1496 },
1497 ),
1498 (
1499 &|x| x.op_wasm_local(1000),
1500 Operation::WasmLocal(1000),
1501 read::Operation::WasmLocal { index: 1000 },
1502 ),
1503 (
1504 &|x| x.op_wasm_global(1000),
1505 Operation::WasmGlobal(1000),
1506 read::Operation::WasmGlobal { index: 1000 },
1507 ),
1508 (
1509 &|x| x.op_wasm_stack(1000),
1510 Operation::WasmStack(1000),
1511 read::Operation::WasmStack { index: 1000 },
1512 ),
1513 ];
1514
1515 let mut expression = Expression::new();
1516 let start_index = expression.next_index();
1517 for (f, o, _) in operations {
1518 f(&mut expression);
1519 assert_eq!(expression.operations.last(), Some(o));
1520 }
1521
1522 let bra_index = expression.op_bra();
1523 let skip_index = expression.op_skip();
1524 expression.op(constants::DW_OP_nop);
1525 let end_index = expression.next_index();
1526 expression.set_target(bra_index, start_index);
1527 expression.set_target(skip_index, end_index);
1528
1529 let mut w = EndianVec::new(LittleEndian);
1530 let mut refs = Vec::new();
1531 expression
1532 .write(&mut w, Some(&mut refs), encoding, Some(&unit_offsets))
1533 .unwrap();
1534 for r in &refs {
1535 assert_eq!(r.unit, unit_id);
1536 assert_eq!(r.entry, entry_id);
1537 w.write_offset_at(
1538 r.offset,
1539 debug_info_offset.0,
1540 SectionId::DebugInfo,
1541 r.size,
1542 )
1543 .unwrap();
1544 }
1545
1546 let read_expression =
1547 read::Expression(read::EndianSlice::new(w.slice(), LittleEndian));
1548 let mut read_operations = read_expression.operations(encoding);
1549 for (_, _, operation) in operations {
1550 assert_eq!(read_operations.next(), Ok(Some(*operation)));
1551 }
1552
1553 // 4 = DW_OP_skip + i16 + DW_OP_nop
1554 assert_eq!(
1555 read_operations.next(),
1556 Ok(Some(read::Operation::Bra {
1557 target: -(w.len() as i16) + 4
1558 }))
1559 );
1560 // 1 = DW_OP_nop
1561 assert_eq!(
1562 read_operations.next(),
1563 Ok(Some(read::Operation::Skip { target: 1 }))
1564 );
1565 assert_eq!(read_operations.next(), Ok(Some(read::Operation::Nop)));
1566 assert_eq!(read_operations.next(), Ok(None));
1567
1568 // Fake the unit.
1569 let unit = read::Unit {
1570 header: read::UnitHeader::new(
1571 encoding,
1572 0,
1573 read::UnitType::Compilation,
1574 DebugAbbrevOffset(0),
1575 DebugInfoOffset(0).into(),
1576 read::EndianSlice::new(&[], LittleEndian),
1577 ),
1578 abbreviations: Arc::new(read::Abbreviations::default()),
1579 name: None,
1580 comp_dir: None,
1581 low_pc: 0,
1582 str_offsets_base: DebugStrOffsetsBase(0),
1583 addr_base: DebugAddrBase(0),
1584 loclists_base: DebugLocListsBase(0),
1585 rnglists_base: DebugRngListsBase(0),
1586 line_program: None,
1587 dwo_id: None,
1588 };
1589
1590 let mut entry_ids = HashMap::new();
1591 entry_ids.insert(debug_info_offset.into(), (unit_id, entry_id));
1592 let convert_expression = Expression::from(
1593 read_expression,
1594 encoding,
1595 None, /* dwarf */
1596 Some(&unit),
1597 Some(&entry_ids),
1598 &|address| Some(Address::Constant(address)),
1599 )
1600 .unwrap();
1601 let mut convert_operations = convert_expression.operations.iter();
1602 for (_, operation, _) in operations {
1603 assert_eq!(convert_operations.next(), Some(operation));
1604 }
1605 assert_eq!(
1606 convert_operations.next(),
1607 Some(&Operation::Branch(start_index))
1608 );
1609 assert_eq!(convert_operations.next(), Some(&Operation::Skip(end_index)));
1610 assert_eq!(
1611 convert_operations.next(),
1612 Some(&Operation::Simple(constants::DW_OP_nop))
1613 );
1614 }
1615 }
1616 }
1617 }
1618}
1619