isa_lang/x86_64/error.rs
1//! Encoding and decoding errors.
2
3use core::fmt;
4
5use super::inst::Mnemonic;
6use super::reg::Reg;
7
8/// Why an instruction could not be encoded.
9///
10/// The encoder tries every form of the mnemonic and reports the failure of
11/// the form that came closest: an operand-kind mismatch only when no form
12/// took the operand kinds at all.
13///
14/// # Examples
15///
16/// ```
17/// use isa_lang::x86_64::{encode, EncodeError, Inst, Mem, Mnemonic, Operand, Reg, Size};
18///
19/// // Memory to memory has no form.
20/// let m = Mem::new(Size::Qword, Reg::RAX);
21/// let err = encode(&Inst::new(Mnemonic::Mov, [m.into(), m.into()])).unwrap_err();
22/// assert_eq!(err, EncodeError::NoForm { mnemonic: Mnemonic::Mov });
23///
24/// // A 64-bit add takes a sign-extended 32-bit immediate at most.
25/// let err = encode(&Inst::new(Mnemonic::Add, [Reg::RAX.into(), Operand::Imm(1 << 40)])).unwrap_err();
26/// assert_eq!(err, EncodeError::ImmediateOutOfRange { value: 1 << 40 });
27/// assert_eq!(err.to_string(), "immediate 0x10000000000 does not fit any form for these operands");
28/// ```
29#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
30#[non_exhaustive]
31pub enum EncodeError {
32 /// No form of the mnemonic takes operands of these kinds, sizes, and
33 /// count. Check the operand order (destination first) and widths.
34 NoForm {
35 /// The mnemonic that was asked for.
36 mnemonic: Mnemonic,
37 },
38 /// Forms take these operand kinds, but the immediate is outside every
39 /// one's range. Immediates are signed values of the operation's width;
40 /// write `-1`, not `0xFFFF_FFFF`, for a 32-bit all-ones value, and load
41 /// wider constants into a register first.
42 ImmediateOutOfRange {
43 /// The immediate as given.
44 value: i64,
45 },
46 /// The branch target is beyond the reach of a 32-bit displacement.
47 TargetOutOfRange {
48 /// The target, relative to the start of the instruction.
49 offset: i64,
50 },
51 /// `AH`, `CH`, `DH`, or `BH` appears in an instruction that needs a REX
52 /// prefix (64-bit operation, `R8`-`R15`, or `SPL`/`BPL`/`SIL`/`DIL`),
53 /// where those encodings mean `SPL`-`DIL` instead. Use another register.
54 HighByteWithRex,
55 /// A memory operand's base register is not a 64-bit register.
56 BaseNotQword {
57 /// The offending base.
58 base: Reg,
59 },
60 /// A memory operand's index register is not a 64-bit register.
61 IndexNotQword {
62 /// The offending index.
63 index: Reg,
64 },
65 /// `RSP` is used as an index register, which the SIB byte cannot express.
66 /// Swap base and index if the scale is 1.
67 RspIndex,
68 /// A RIP-relative memory operand has an index register.
69 RipWithIndex,
70}
71
72impl fmt::Display for EncodeError {
73 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74 match self {
75 EncodeError::NoForm { mnemonic } => {
76 write!(f, "no `{mnemonic}` form takes these operands")
77 }
78 EncodeError::ImmediateOutOfRange { value } => {
79 f.write_str("immediate ")?;
80 super::fmt::hex(f, *value)?;
81 f.write_str(" does not fit any form for these operands")
82 }
83 EncodeError::TargetOutOfRange { offset } => {
84 f.write_str("branch target $")?;
85 super::fmt::signed_hex(f, *offset)?;
86 f.write_str(" is out of reach of a 32-bit displacement")
87 }
88 EncodeError::HighByteWithRex => f.write_str(
89 "ah, ch, dh, and bh cannot be used in an instruction that needs a REX prefix",
90 ),
91 EncodeError::BaseNotQword { base } => {
92 write!(f, "memory base `{base}` is not a 64-bit register")
93 }
94 EncodeError::IndexNotQword { index } => {
95 write!(f, "memory index `{index}` is not a 64-bit register")
96 }
97 EncodeError::RspIndex => f.write_str("rsp cannot be an index register"),
98 EncodeError::RipWithIndex => {
99 f.write_str("a rip-relative memory operand cannot have an index register")
100 }
101 }
102 }
103}
104
105impl core::error::Error for EncodeError {}
106
107/// Why bytes could not be decoded.
108///
109/// Every variant carries `at`, the offset in the input of the byte at fault.
110/// The decoder accepts exactly the encodings the form table describes, plus
111/// a redundant empty REX prefix (`40`) and a redundant REX.W on 64-bit-default
112/// forms; anything else is an error, never a guess.
113///
114/// # Examples
115///
116/// ```
117/// use isa_lang::x86_64::{decode, DecodeError};
118///
119/// assert_eq!(decode(&[0x48, 0x83]), Err(DecodeError::Truncated { at: 2 }));
120/// assert_eq!(decode(&[0xF0, 0x01, 0xC0]), Err(DecodeError::UnsupportedPrefix { at: 0, byte: 0xF0 }));
121/// assert_eq!(decode(&[0x0F, 0x05]), Err(DecodeError::UnknownOpcode { at: 1, escaped: true, opcode: 0x05 }));
122/// assert_eq!(
123/// decode(&[0x0F, 0x05]).unwrap_err().to_string(),
124/// "unknown opcode 0f 05 at byte 1",
125/// );
126/// ```
127#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
128#[non_exhaustive]
129pub enum DecodeError {
130 /// The input ends before the instruction does.
131 Truncated {
132 /// The offset at which another byte was needed.
133 at: usize,
134 },
135 /// A legacy prefix outside the supported set (only `66` is supported:
136 /// no LOCK, REP, segment, or address-size prefixes).
137 UnsupportedPrefix {
138 /// Offset of the prefix.
139 at: usize,
140 /// The prefix byte.
141 byte: u8,
142 },
143 /// The operand-size prefix `66` appears twice.
144 RepeatedPrefix {
145 /// Offset of the second `66`.
146 at: usize,
147 },
148 /// A REX prefix is followed by another prefix instead of the opcode.
149 MisplacedRex {
150 /// Offset of the REX prefix.
151 at: usize,
152 },
153 /// No form has this opcode.
154 UnknownOpcode {
155 /// Offset of the opcode byte.
156 at: usize,
157 /// Whether the opcode follows the `0F` escape.
158 escaped: bool,
159 /// The opcode byte.
160 opcode: u8,
161 },
162 /// The opcode exists, but not with this operand size (`66` / REX.W).
163 InvalidOperandSize {
164 /// Offset of the opcode byte.
165 at: usize,
166 },
167 /// The opcode exists, but not with this ModRM `reg` extension.
168 UnknownExtension {
169 /// Offset of the ModRM byte.
170 at: usize,
171 /// The `/digit` found.
172 ext: u8,
173 },
174 /// The form needs a memory operand but ModRM names a register.
175 RegisterOperand {
176 /// Offset of the ModRM byte.
177 at: usize,
178 },
179 /// The REX prefix sets R, X, or B, but no operand of the form uses it.
180 UnusedRex {
181 /// Offset of the REX prefix.
182 at: usize,
183 },
184}
185
186impl DecodeError {
187 /// The offset in the input of the byte at fault.
188 ///
189 /// # Examples
190 ///
191 /// ```
192 /// use isa_lang::x86_64::decode;
193 ///
194 /// assert_eq!(decode(&[0x66, 0x66, 0x90]).unwrap_err().at(), 1);
195 /// ```
196 #[must_use]
197 pub const fn at(&self) -> usize {
198 match *self {
199 DecodeError::Truncated { at }
200 | DecodeError::UnsupportedPrefix { at, .. }
201 | DecodeError::RepeatedPrefix { at }
202 | DecodeError::MisplacedRex { at }
203 | DecodeError::UnknownOpcode { at, .. }
204 | DecodeError::InvalidOperandSize { at }
205 | DecodeError::UnknownExtension { at, .. }
206 | DecodeError::RegisterOperand { at }
207 | DecodeError::UnusedRex { at } => at,
208 }
209 }
210}
211
212impl fmt::Display for DecodeError {
213 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214 match *self {
215 DecodeError::Truncated { at } => {
216 write!(
217 f,
218 "instruction is cut off: byte {at} is past the end of the input"
219 )
220 }
221 DecodeError::UnsupportedPrefix { at, byte } => {
222 write!(f, "unsupported prefix {byte:02x} at byte {at}")
223 }
224 DecodeError::RepeatedPrefix { at } => {
225 write!(f, "repeated operand-size prefix at byte {at}")
226 }
227 DecodeError::MisplacedRex { at } => {
228 write!(
229 f,
230 "REX prefix at byte {at} is not immediately before the opcode"
231 )
232 }
233 DecodeError::UnknownOpcode {
234 at,
235 escaped,
236 opcode,
237 } => {
238 let escape = if escaped { "0f " } else { "" };
239 write!(f, "unknown opcode {escape}{opcode:02x} at byte {at}")
240 }
241 DecodeError::InvalidOperandSize { at } => {
242 write!(f, "opcode at byte {at} has no form with this operand size")
243 }
244 DecodeError::UnknownExtension { at, ext } => {
245 write!(
246 f,
247 "opcode extension /{ext} in the ModRM byte at {at} is not defined"
248 )
249 }
250 DecodeError::RegisterOperand { at } => {
251 write!(
252 f,
253 "ModRM byte at {at} names a register where memory is required"
254 )
255 }
256 DecodeError::UnusedRex { at } => {
257 write!(f, "REX prefix at byte {at} sets a bit no operand uses")
258 }
259 }
260 }
261}
262
263impl core::error::Error for DecodeError {}