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