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