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