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 | |