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