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