xref: /wasmtime-44.0.1/pulley/src/decode.rs (revision dfc4358d)
1 //! Decoding support for pulley bytecode.
2 
3 use alloc::vec::Vec;
4 
5 use crate::imms::*;
6 use crate::opcode::*;
7 use crate::regs::*;
8 
9 /// Either an `Ok(T)` or an `Err(DecodingError)`.
10 pub type Result<T, E = DecodingError> = core::result::Result<T, E>;
11 
12 /// An error when decoding Pulley bytecode.
13 pub enum DecodingError {
14     /// Reached the end of the bytecode stream before we finished decoding a
15     /// single bytecode.
16     UnexpectedEof {
17         /// The position in the bytecode stream where this error occurred.
18         position: usize,
19     },
20 
21     /// Found an invalid opcode.
22     InvalidOpcode {
23         /// The position in the bytecode stream where this error occurred.
24         position: usize,
25         /// The invalid opcode that was found.
26         code: u8,
27     },
28 
29     /// Found an invalid extended opcode.
30     InvalidExtendedOpcode {
31         /// The position in the bytecode stream where this error occurred.
32         position: usize,
33         /// The invalid extended opcode that was found.
34         code: u16,
35     },
36 
37     /// Found an invalid register.
38     InvalidReg {
39         /// The position in the bytecode stream where this error occurred.
40         position: usize,
41         /// The invalid register that was found.
42         reg: u8,
43     },
44 }
45 
46 impl core::fmt::Debug for DecodingError {
47     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
48         core::fmt::Display::fmt(self, f)
49     }
50 }
51 
52 impl core::fmt::Display for DecodingError {
53     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
54         match self {
55             Self::UnexpectedEof { position } => {
56                 write!(f, "unexpected end-of-file at bytecode offset {position:#x}")
57             }
58             Self::InvalidOpcode { position, code } => {
59                 write!(
60                     f,
61                     "found invalid opcode {code:#x} at bytecode offset {position:#x}"
62                 )
63             }
64             Self::InvalidExtendedOpcode { position, code } => {
65                 write!(
66                     f,
67                     "found invalid opcode {code:#x} at bytecode offset {position:#x}"
68                 )
69             }
70             Self::InvalidReg { position, reg } => {
71                 write!(
72                     f,
73                     "found invalid register {reg:#x} at bytecode offset {position:#x}"
74                 )
75             }
76         }
77     }
78 }
79 
80 #[cfg(feature = "std")]
81 impl std::error::Error for DecodingError {}
82 
83 /// An abstraction over any kind of bytecode stream.
84 ///
85 /// There are two primary implementations:
86 ///
87 /// 1. `SafeBytecodeStream`: A thin wrapper around an index into a `&[u8]`. This
88 ///    implementation is 100% safe code.
89 ///
90 /// 2. `UnsafeBytecodeStream`: A thin wrapper over a raw pointer. This
91 ///    implementation is wildly unsafe and will result in memory unsafety and
92 ///    other terrors when given invalid bytecode, or even valid bytecode
93 ///    encoding a program that itself does not preserve memory safety.
94 pub trait BytecodeStream: Copy {
95     /// The type of error that this bytecode stream produces on invalid
96     /// operations.
97     type Error;
98 
99     /// Create an "unexpected end-of-stream" error at the current position.
100     fn unexpected_eof(&self) -> Self::Error;
101 
102     /// Create an "invalid opcode" error at the current position.
103     fn invalid_opcode(&self, code: u8) -> Self::Error;
104 
105     /// Create an "invalid extended opcode" error at the current position.
106     fn invalid_extended_opcode(&self, code: u16) -> Self::Error;
107 
108     /// Create an "invalid register" error at the current position.
109     fn invalid_reg(&self, reg: u8) -> Self::Error;
110 
111     /// Read `N` bytes from this bytecode stream, advancing the stream's
112     /// position at the same time.
113     fn read<const N: usize>(&mut self) -> Result<[u8; N], Self::Error>;
114 }
115 
116 /// A 100% safe implementation of a bytecode stream.
117 ///
118 /// This is a thin wrapper around an index into a `&[u8]`.
119 #[derive(Clone, Copy, Debug)]
120 pub struct SafeBytecodeStream<'a> {
121     bytecode: &'a [u8],
122     position: usize,
123 }
124 
125 impl<'a> SafeBytecodeStream<'a> {
126     /// Create a new `SafeBytecodeStream` from the given slice and with an
127     /// initial position pointing at the start of the slice.
128     pub fn new(bytecode: &'a [u8]) -> Self {
129         Self {
130             bytecode,
131             position: 0,
132         }
133     }
134 
135     /// Get this stream's current position within its underlying slice.
136     pub fn position(&self) -> usize {
137         self.position
138     }
139 
140     /// Get this stream's underlying bytecode slice.
141     pub fn as_slice(&self) -> &[u8] {
142         &self.bytecode
143     }
144 }
145 
146 impl BytecodeStream for SafeBytecodeStream<'_> {
147     fn read<const N: usize>(&mut self) -> Result<[u8; N], Self::Error> {
148         let bytes = *self
149             .bytecode
150             .first_chunk::<N>()
151             .ok_or_else(|| self.unexpected_eof())?;
152         self.bytecode = &self.bytecode[N..];
153         self.position += N;
154         Ok(bytes)
155     }
156 
157     type Error = DecodingError;
158 
159     fn unexpected_eof(&self) -> Self::Error {
160         DecodingError::UnexpectedEof {
161             position: self.position,
162         }
163     }
164 
165     fn invalid_opcode(&self, code: u8) -> Self::Error {
166         DecodingError::InvalidOpcode {
167             position: self.position - 1,
168             code,
169         }
170     }
171 
172     fn invalid_extended_opcode(&self, code: u16) -> Self::Error {
173         DecodingError::InvalidExtendedOpcode {
174             position: self.position,
175             code,
176         }
177     }
178 
179     fn invalid_reg(&self, reg: u8) -> Self::Error {
180         DecodingError::InvalidReg {
181             position: self.position,
182             reg,
183         }
184     }
185 }
186 
187 /// An uninhabited type that cannot be constructed at runtime.
188 #[derive(Debug)]
189 pub enum Uninhabited {}
190 
191 /// An unsafe bytecode stream.
192 ///
193 /// This is a wrapper over a raw pointer to bytecode somewhere in memory.
194 #[derive(Clone, Copy, Debug)]
195 pub struct UnsafeBytecodeStream(*mut u8);
196 
197 impl UnsafeBytecodeStream {
198     /// Construct a new `UnsafeBytecodeStream` pointing at the given PC.
199     ///
200     /// # Safety
201     ///
202     /// The given `pc` must point to valid Pulley bytecode, and it is the
203     /// caller's responsibility to ensure that the resulting
204     /// `UnsafeBytecodeStream` is only used to access the valid bytecode. For
205     /// example, if the current bytecode instruction unconditionally jumps to a
206     /// new PC, this stream must not be used to read just after the
207     /// unconditional jump instruction because there is no guarantee that that
208     /// memory is part of the bytecode stream or not.
209     pub unsafe fn new(pc: *mut u8) -> Self {
210         assert!(!pc.is_null());
211         UnsafeBytecodeStream(pc)
212     }
213 
214     /// Get a new `UnsafeBytecodeStream` pointing at the bytecode that is at the
215     /// given relative offset from this stream's current position.
216     ///
217     /// # Safety
218     ///
219     /// Same as the `new` constructor. May only be used when it is guaranteed
220     /// that the address at `self._as_ptr() + offset` contains valid Pulley
221     /// bytecode.
222     pub unsafe fn offset(&self, offset: isize) -> Self {
223         UnsafeBytecodeStream(self.0.offset(offset))
224     }
225 
226     /// Get this stream's underlying raw pointer.
227     pub fn as_ptr(&self) -> *mut u8 {
228         self.0
229     }
230 }
231 
232 impl BytecodeStream for UnsafeBytecodeStream {
233     fn read<const N: usize>(&mut self) -> Result<[u8; N], Self::Error> {
234         debug_assert!(!self.0.is_null());
235         let bytes = unsafe { self.0.cast::<[u8; N]>().read() };
236         self.0 = unsafe { self.0.add(N) };
237         Ok(bytes)
238     }
239 
240     type Error = Uninhabited;
241 
242     fn unexpected_eof(&self) -> Self::Error {
243         unsafe { crate::unreachable_unchecked() }
244     }
245 
246     fn invalid_opcode(&self, _code: u8) -> Self::Error {
247         unsafe { crate::unreachable_unchecked() }
248     }
249 
250     fn invalid_extended_opcode(&self, _code: u16) -> Self::Error {
251         unsafe { crate::unreachable_unchecked() }
252     }
253 
254     fn invalid_reg(&self, _reg: u8) -> Self::Error {
255         unsafe { crate::unreachable_unchecked() }
256     }
257 }
258 
259 /// Anything that can be decoded from a bytecode stream, e.g. opcodes,
260 /// immediates, registers, etc...
261 trait Decode: Sized {
262     fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
263     where
264         T: BytecodeStream;
265 }
266 
267 impl Decode for u8 {
268     fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
269     where
270         T: BytecodeStream,
271     {
272         bytecode.read::<1>().map(|a| a[0])
273     }
274 }
275 
276 impl Decode for u16 {
277     fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
278     where
279         T: BytecodeStream,
280     {
281         Ok(u16::from_le_bytes(bytecode.read()?))
282     }
283 }
284 
285 impl Decode for u32 {
286     fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
287     where
288         T: BytecodeStream,
289     {
290         Ok(u32::from_le_bytes(bytecode.read()?))
291     }
292 }
293 
294 impl Decode for u64 {
295     fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
296     where
297         T: BytecodeStream,
298     {
299         Ok(u64::from_le_bytes(bytecode.read()?))
300     }
301 }
302 
303 impl Decode for i8 {
304     fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
305     where
306         T: BytecodeStream,
307     {
308         bytecode.read::<1>().map(|a| a[0] as i8)
309     }
310 }
311 
312 impl Decode for i16 {
313     fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
314     where
315         T: BytecodeStream,
316     {
317         Ok(i16::from_le_bytes(bytecode.read()?))
318     }
319 }
320 
321 impl Decode for i32 {
322     fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
323     where
324         T: BytecodeStream,
325     {
326         Ok(i32::from_le_bytes(bytecode.read()?))
327     }
328 }
329 
330 impl Decode for i64 {
331     fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
332     where
333         T: BytecodeStream,
334     {
335         Ok(i64::from_le_bytes(bytecode.read()?))
336     }
337 }
338 
339 impl Decode for XReg {
340     fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
341     where
342         T: BytecodeStream,
343     {
344         let byte = u8::decode(bytecode)?;
345         XReg::new(byte).ok_or_else(|| bytecode.invalid_reg(byte))
346     }
347 }
348 
349 impl Decode for FReg {
350     fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
351     where
352         T: BytecodeStream,
353     {
354         let byte = u8::decode(bytecode)?;
355         FReg::new(byte).ok_or_else(|| bytecode.invalid_reg(byte))
356     }
357 }
358 
359 impl Decode for VReg {
360     fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
361     where
362         T: BytecodeStream,
363     {
364         let byte = u8::decode(bytecode)?;
365         VReg::new(byte).ok_or_else(|| bytecode.invalid_reg(byte))
366     }
367 }
368 
369 impl Decode for PcRelOffset {
370     fn decode<T>(bytecode: &mut T) -> Result<Self, T::Error>
371     where
372         T: BytecodeStream,
373     {
374         i32::decode(bytecode).map(|x| Self::from(x))
375     }
376 }
377 
378 /// A Pulley bytecode decoder.
379 ///
380 /// Does not materialize bytecode instructions, instead all decoding methods are
381 /// given an `OpVisitor` implementation and the appropriate visitor methods are
382 /// called upon decoding an instruction. This minimizes the amount of times we
383 /// branch on the opcode, avoids constructing temporary storage, and plays well
384 /// with our variable-length instruction encoding.
385 #[derive(Default)]
386 pub struct Decoder {
387     _private: (),
388 }
389 
390 impl Decoder {
391     /// Create a new decoder.
392     pub fn new() -> Self {
393         Self::default()
394     }
395 
396     /// Decode all instructions in the visitor's bytecode stream.
397     ///
398     /// The associated visitor method is invoked after each instruction is
399     /// decoded.
400     pub fn decode_all<'a, V>(visitor: &mut V) -> Result<Vec<V::Return>>
401     where
402         V: OpVisitor<BytecodeStream = SafeBytecodeStream<'a>> + ExtendedOpVisitor,
403     {
404         let mut decoder = Decoder::new();
405         let mut results = Vec::new();
406 
407         while !visitor.bytecode().as_slice().is_empty() {
408             results.push(decoder.decode_one(visitor)?);
409         }
410 
411         Ok(results)
412     }
413 }
414 
415 /// An `OpVisitor` combinator to sequence one visitor and then another.
416 pub struct SequencedVisitor<'a, F, V1, V2> {
417     join: F,
418     v1: &'a mut V1,
419     v2: &'a mut V2,
420 }
421 
422 impl<'a, F, V1, V2> SequencedVisitor<'a, F, V1, V2> {
423     /// Create a new sequenced visitor.
424     ///
425     /// The given `join` function is used to combine the results of each
426     /// sub-visitor so that it can be returned from this combined visitor.
427     pub fn new(join: F, v1: &'a mut V1, v2: &'a mut V2) -> Self {
428         SequencedVisitor { join, v1, v2 }
429     }
430 }
431 
432 macro_rules! define_decoder {
433     (
434         $(
435             $( #[$attr:meta] )*
436                 $snake_name:ident = $name:ident $( {
437                 $(
438                     $( #[$field_attr:meta] )*
439                     $field:ident : $field_ty:ty
440                 ),*
441             } )? ;
442         )*
443     ) => {
444         impl Decoder {
445             /// Decode one instruction from the visitor's bytestream.
446             ///
447             /// Upon decoding, the visitor's associated callback is invoked and
448             /// the results returned.
449             #[inline(always)]
450             pub fn decode_one<V>(
451                 &mut self,
452                 visitor: &mut V,
453             ) -> Result<V::Return, <V::BytecodeStream as BytecodeStream>::Error>
454             where
455                 V: OpVisitor + ExtendedOpVisitor,
456             {
457                 visitor.before_visit();
458 
459                 let byte = u8::decode(visitor.bytecode())?;
460                 let opcode = Opcode::new(byte).ok_or_else(|| {
461                     visitor.bytecode().invalid_opcode(byte)
462                 })?;
463 
464                 match opcode {
465                     $(
466                         Opcode::$name => {
467                             $(
468                                 $(
469                                     let $field = <$field_ty>::decode(
470                                         visitor.bytecode(),
471                                     )?;
472                                 )*
473                             )?
474 
475                             let ret = visitor.$snake_name($( $( $field ),* )?);
476                             visitor.after_visit();
477                             Ok(ret)
478                         },
479                     )*
480                     Opcode::ExtendedOp => {
481                         decode_one_extended(visitor)
482                     }
483                 }
484             }
485         }
486 
487         /// Callbacks upon decoding instructions from bytecode.
488         ///
489         /// Implement this trait for your type, give an instance of your type to
490         /// a `Decoder` method, and the `Decoder` will invoke the associated
491         /// method for each instruction that it decodes. For example, if the
492         /// `Decoder` decodes an `xadd32` instruction, then it will invoke the
493         /// `xadd32` visitor method, passing along any decoded immediates,
494         /// operands, etc... as arguments.
495         pub trait OpVisitor {
496             /// The type of this visitor's bytecode stream.
497             type BytecodeStream: BytecodeStream;
498 
499             /// Get this visitor's underlying bytecode stream.
500             fn bytecode(&mut self) -> &mut Self::BytecodeStream;
501 
502             /// The type of values returned by each visitor method.
503             type Return;
504 
505             /// A callback invoked before starting to decode an instruction.
506             ///
507             /// Does nothing by default.
508             fn before_visit(&mut self) {}
509 
510             /// A callback invoked after an instruction has been completely
511             /// decoded.
512             ///
513             /// Does nothing by default.
514             fn after_visit(&mut self) {}
515 
516             $(
517                 $( #[$attr] )*
518                 fn $snake_name(&mut self $( $( , $field : $field_ty )* )? ) -> Self::Return;
519             )*
520         }
521 
522         impl<F, T, V1, V2> OpVisitor for SequencedVisitor<'_, F, V1, V2>
523         where
524             F: FnMut(V1::Return, V2::Return) -> T,
525             V1: OpVisitor,
526             V2: OpVisitor<BytecodeStream = V1::BytecodeStream>,
527         {
528             type BytecodeStream = V1::BytecodeStream;
529 
530             fn bytecode(&mut self) -> &mut Self::BytecodeStream {
531                 self.v1.bytecode()
532             }
533 
534             type Return = T;
535 
536             fn before_visit(&mut self) {
537                 self.v1.before_visit();
538                 self.v2.before_visit();
539             }
540 
541             fn after_visit(&mut self) {
542                 *self.v2.bytecode() = *self.v1.bytecode();
543                 self.v1.after_visit();
544                 self.v2.after_visit();
545             }
546 
547             $(
548                 $( #[$attr] )*
549                 fn $snake_name(&mut self $( $( , $field : $field_ty )* )? ) -> Self::Return {
550                     let a = self.v1.$snake_name( $( $( $field , )* )? );
551                     let b = self.v2.$snake_name( $( $( $field , )* )? );
552                     (self.join)(a, b)
553                 }
554             )*
555         }
556     };
557 }
558 for_each_op!(define_decoder);
559 
560 macro_rules! define_extended_decoder {
561     (
562         $(
563             $( #[$attr:meta] )*
564                 $snake_name:ident = $name:ident $( {
565                 $(
566                     $( #[$field_attr:meta] )*
567                     $field:ident : $field_ty:ty
568                 ),*
569             } )? ;
570         )*
571     ) => {
572         /// Like `OpVisitor` but for extended operations.
573         pub trait ExtendedOpVisitor: OpVisitor {
574             $(
575                 $( #[$attr] )*
576                 fn $snake_name(&mut self $( $( , $field : $field_ty )* )? ) -> Self::Return;
577             )*
578         }
579 
580         fn decode_one_extended<V>(
581             visitor: &mut V,
582         ) -> Result<V::Return, <V::BytecodeStream as BytecodeStream>::Error>
583         where
584             V: ExtendedOpVisitor,
585         {
586             let code = u16::decode(visitor.bytecode())?;
587             let opcode = ExtendedOpcode::new(code).ok_or_else(|| {
588                 visitor.bytecode().invalid_extended_opcode(code)
589             })?;
590 
591             match opcode {
592                 $(
593                     ExtendedOpcode::$name => {
594                         $(
595                             $(
596                                 let $field = <$field_ty>::decode(
597                                     visitor.bytecode(),
598                                 )?;
599                             )*
600                         )?
601 
602                         let ret = visitor.$snake_name($( $( $field ),* )?);
603                         visitor.after_visit();
604                         Ok(ret)
605                     }
606                 )*
607             }
608         }
609 
610 
611         impl<F, T, V1, V2> ExtendedOpVisitor for SequencedVisitor<'_, F, V1, V2>
612         where
613             F: FnMut(V1::Return, V2::Return) -> T,
614             V1: ExtendedOpVisitor,
615             V2: ExtendedOpVisitor<BytecodeStream = V1::BytecodeStream>,
616         {
617             $(
618                 $( #[$attr] )*
619                 fn $snake_name(&mut self $( $( , $field : $field_ty )* )? ) -> Self::Return {
620                     let a = self.v1.$snake_name( $( $( $field , )* )? );
621                     let b = self.v2.$snake_name( $( $( $field , )* )? );
622                     (self.join)(a, b)
623                 }
624             )*
625         }
626     };
627 }
628 for_each_extended_op!(define_extended_decoder);
629