diff options
| -rw-r--r-- | src/long_mode/mod.rs | 337 | 
1 files changed, 166 insertions, 171 deletions
diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs index 7ab5f7d..8be5f61 100644 --- a/src/long_mode/mod.rs +++ b/src/long_mode/mod.rs @@ -6422,53 +6422,29 @@ fn read_with_annotations<      words.mark();      let mut nextb = words.next().ok().ok_or(DecodeError::ExhaustedInput)?;      let mut next_rec = OPCODES[nextb as usize]; -    let mut prefixes = Prefixes::new(0); +    instruction.prefixes = Prefixes::new(0);      // default x86_64 registers to `[rax; 4]`      instruction.regs = unsafe { core::mem::transmute(0u64) }; -    instruction.mem_size = 0;      // default operands to [RegRRR, Nothing, Nothing, Nothing]      instruction.operands = unsafe { core::mem::transmute(0x00_00_00_01) }; -    instruction.operand_count = 2; -    let record: OpcodeRecord = loop { -        let record = next_rec; -        if nextb >= 0x40 && nextb < 0x50 { -            let b = nextb; -            sink.record((words.offset() - 1) as u32 * 8, (words.offset() - 1) as u32 * 8 + 7, FieldDescription { -                desc: InnerDescription::RexPrefix(b), -                id: words.offset() as u32 * 8 - 8, -            }); -            if words.offset() >= 15 { -                return Err(DecodeError::TooLong); -            } -            nextb = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; -            next_rec = unsafe { -                core::ptr::read_volatile(&OPCODES[nextb as usize]) -            }; -            prefixes.rex_from(b); -        } else if let Interpretation::Instruction(opc) = record.0 { -            if words.offset() > 1 { -                sink.record( -                    words.offset() as u32 * 8 - 8 - 1, words.offset() as u32 * 8 - 8 - 1, -                    InnerDescription::Boundary("prefixes end") -                        .with_id(words.offset() as u32 * 8 - 9) -                ); -            } -            if opc != Opcode::Invalid { +    let record: OperandCode = { +        let prefixes = &mut instruction.prefixes; +        let record = loop { +            let record = next_rec; +            if nextb >= 0x40 && nextb < 0x50 { +                let b = nextb;                  sink.record((words.offset() - 1) as u32 * 8, (words.offset() - 1) as u32 * 8 + 7, FieldDescription { -                    desc: InnerDescription::Opcode(opc), +                    desc: InnerDescription::RexPrefix(b),                      id: words.offset() as u32 * 8 - 8,                  }); -            } -            sink.record((words.offset() - 1) as u32 * 8, (words.offset() - 1) as u32 * 8 + 7, FieldDescription { -                desc: InnerDescription::OperandCode(OperandCodeWrapper { code: record.1 }), -                id: words.offset() as u32 * 8 - 8 + 1, -            }); -            break record; -        } else { -            let b = nextb; -            if b == 0x0f { +                nextb = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; +                next_rec = unsafe { +                    core::ptr::read_volatile(&OPCODES[nextb as usize]) +                }; +                prefixes.rex_from(b); +            } else if let Interpretation::Instruction(opc) = record.0 {                  if words.offset() > 1 {                      sink.record(                          words.offset() as u32 * 8 - 8 - 1, words.offset() as u32 * 8 - 8 - 1, @@ -6476,126 +6452,49 @@ fn read_with_annotations<                              .with_id(words.offset() as u32 * 8 - 9)                      );                  } -                let b = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; -                if b == 0x38 { -                    let b = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; -                    break read_0f38_opcode(b, &mut prefixes); -                } else if b == 0x3a { -                    let b = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; -                    break read_0f3a_opcode(b, &mut prefixes); -                } else { -                    break read_0f_opcode(b, &mut prefixes); -                } -            } -            // some prefix seen after we saw rex, but before the 0f escape or an actual -            // opcode. so we must forget the rex prefix! -            // this is to handle sequences like 41660f21cf -            // where if 660f21 were a valid opcode, 41 would apply a rex.b -            // prefix, but since 660f21 is not valid, the opcode is interpreted -            // as 0f21, where 66 is a prefix, which makes 41 not the last -            // prefix before the opcode, and it's discarded. - -            // 2.3.2 -            // Any VEX-encoded instruction with a LOCK prefix preceding VEX will #UD. -            // 2.3.3 -            // Any VEX-encoded instruction with a 66H, F2H, or F3H prefix preceding VEX -            // will #UD. -            // 2.3.4 -            // Any VEX-encoded instruction with a REX prefix proceeding VEX will #UD.  -            if b == 0xc5 { -                if prefixes.rex_unchecked().present() || prefixes.lock() || prefixes.operand_size() || prefixes.rep() || prefixes.repnz() { -                    // rex and then vex is invalid! reject it. -                    return Err(DecodeError::InvalidPrefixes); -                } else { -                    instruction.prefixes = prefixes; -                    sink.record( -                        words.offset() as u32 * 8 - 8, -                        words.offset() as u32 * 8 - 1, -                        InnerDescription::Misc("two-byte vex prefix (0xc5)") -                            .with_id(words.offset() as u32 * 8 - 8) -                    ); -                    vex::two_byte_vex(words, instruction, sink)?; -                    return Ok(()); -                } -            } else if b == 0xc4 { -                if prefixes.rex_unchecked().present() || prefixes.lock() || prefixes.operand_size() || prefixes.rep() || prefixes.repnz() { -                    // rex and then vex is invalid! reject it. -                    return Err(DecodeError::InvalidPrefixes); -                } else { -                    instruction.prefixes = prefixes; -                    sink.record( -                        words.offset() as u32 * 8 - 8, -                        words.offset() as u32 * 8 - 1, -                        InnerDescription::Misc("three-byte vex prefix (0xc4)") -                            .with_id(words.offset() as u32 * 8 - 8) -                    ); -                    vex::three_byte_vex(words, instruction, sink)?; -                    return Ok(()); -                } -            } else if b == 0x62 { -                if prefixes.rex_unchecked().present() || prefixes.lock() || prefixes.operand_size() || prefixes.rep() || prefixes.repnz() { -                    // rex and then evex is invalid! reject it. -                    return Err(DecodeError::InvalidPrefixes); -                } else { -                    instruction.prefixes = prefixes; -                    sink.record( -                        words.offset() as u32 * 8 - 8, -                        words.offset() as u32 * 8 - 1, -                        InnerDescription::Misc("evex prefix (0x62)") -                            .with_id(words.offset() as u32 * 8 - 8) -                    ); -                    evex::read_evex(words, instruction, None, sink)?; -                    return Ok(()); +                if opc != Opcode::Invalid { +                    sink.record((words.offset() - 1) as u32 * 8, (words.offset() - 1) as u32 * 8 + 7, FieldDescription { +                        desc: InnerDescription::Opcode(opc), +                        id: words.offset() as u32 * 8 - 8, +                    });                  } -            } - -            nextb = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; -            next_rec = unsafe { -                core::ptr::read_volatile(&OPCODES[nextb as usize]) -            }; -            if words.offset() >= 15 { -                return Err(DecodeError::TooLong); -            } -            if prefixes.rex.bits != 0 { -                sink.record((words.offset() - 2) as u32 * 8, (words.offset() - 2) as u32 * 8 + 7, FieldDescription { -                    desc: InnerDescription::Misc("invalidates prior rex prefix"), -                    id: (words.offset() as u32 * 8 - 16) + 1, +                sink.record((words.offset() - 1) as u32 * 8, (words.offset() - 1) as u32 * 8 + 7, FieldDescription { +                    desc: InnerDescription::OperandCode(OperandCodeWrapper { code: record.1 }), +                    id: words.offset() as u32 * 8 - 8 + 1,                  }); -            } -            prefixes.rex_from(0); -            match b { -                0x26 | -                0x2e | -                0x36 | -                0x3e => { -                    /* no-op in amd64 */ -                    sink.record((words.offset() - 2) as u32 * 8, (words.offset() - 2) as u32 * 8 + 7, FieldDescription { -                        desc: InnerDescription::Misc("ignored prefix in 64-bit mode"), -                        id: words.offset() as u32 * 8 - 16, -                    }); -                }, -                0x64 => { -                    sink.record((words.offset() - 2) as u32 * 8, (words.offset() - 2) as u32 * 8 + 7, FieldDescription { -                        desc: InnerDescription::SegmentPrefix(Segment::FS), -                        id: words.offset() as u32 * 8 - 16, -                    }); -                    prefixes.set_fs(); -                }, -                0x65 => { -                    sink.record((words.offset() - 2) as u32 * 8, (words.offset() - 2) as u32 * 8 + 7, FieldDescription { -                        desc: InnerDescription::SegmentPrefix(Segment::GS), -                        id: words.offset() as u32 * 8 - 16, -                    }); -                    prefixes.set_gs(); -                }, -                0x66 => { +                instruction.mem_size = 0; +                instruction.operand_count = 2; +                break record; +            } else { +                let b = nextb; +                if b == 0x0f { +                    if words.offset() > 1 { +                        sink.record( +                            words.offset() as u32 * 8 - 8 - 1, words.offset() as u32 * 8 - 8 - 1, +                            InnerDescription::Boundary("prefixes end") +                                .with_id(words.offset() as u32 * 8 - 9) +                        ); +                    } +                    let b = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; +                    instruction.mem_size = 0; +                    instruction.operand_count = 2; +                    if b == 0x38 { +                        let b = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; +                        break read_0f38_opcode(b, prefixes); +                    } else if b == 0x3a { +                        let b = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; +                        break read_0f3a_opcode(b, prefixes); +                    } else { +                        break read_0f_opcode(b, prefixes); +                    } +                } +                if b == 0x66 {                      sink.record((words.offset() - 2) as u32 * 8, (words.offset() - 2) as u32 * 8 + 7, FieldDescription {                          desc: InnerDescription::Misc("operand size override (to 16 bits)"),                          id: words.offset() as u32 * 8 - 16,                      });                      prefixes.set_operand_size(); -                }, -                0x67 => { +                } else if b == 0x67 {                      sink.record((words.offset() - 2) as u32 * 8, (words.offset() - 2) as u32 * 8 + 7, FieldDescription {                          desc: InnerDescription::Misc("address size override (to 32 bits)"),                          id: words.offset() as u32 * 8 - 16, @@ -6603,39 +6502,80 @@ fn read_with_annotations<                      prefixes.set_address_size();                      instruction.regs[1].bank = RegisterBank::D;                      instruction.regs[2].bank = RegisterBank::D; -                }, -                0xf0 => { -                    sink.record((words.offset() - 2) as u32 * 8, (words.offset() - 2) as u32 * 8 + 7, FieldDescription { -                        desc: InnerDescription::Misc("lock prefix"), -                        id: words.offset() as u32 * 8 - 16, -                    }); -                    prefixes.set_lock(); -                }, -                0xf2 => { +                } else if b == 0xf2 {                      sink.record((words.offset() - 2) as u32 * 8, (words.offset() - 2) as u32 * 8 + 7, FieldDescription {                          desc: InnerDescription::Misc("repnz prefix"),                          id: words.offset() as u32 * 8 - 16,                      });                      prefixes.set_repnz(); -                }, -                0xf3 => { +                } else if b == 0xf3 {                      sink.record((words.offset() - 2) as u32 * 8, (words.offset() - 2) as u32 * 8 + 7, FieldDescription {                          desc: InnerDescription::Misc("rep prefix"),                          id: words.offset() as u32 * 8 - 16,                      });                      prefixes.set_rep(); -                }, -                _ => { unsafe { unreachable_unchecked(); } } +                } else { +                    match b { +                        0x26 | +                        0x2e | +                        0x36 | +                        0x3e => { +                            /* no-op in amd64 */ +                            sink.record((words.offset() - 2) as u32 * 8, (words.offset() - 2) as u32 * 8 + 7, FieldDescription { +                                desc: InnerDescription::Misc("ignored prefix in 64-bit mode"), +                                id: words.offset() as u32 * 8 - 16, +                            }); +                        }, +                        0x64 => { +                            sink.record((words.offset() - 2) as u32 * 8, (words.offset() - 2) as u32 * 8 + 7, FieldDescription { +                                desc: InnerDescription::SegmentPrefix(Segment::FS), +                                id: words.offset() as u32 * 8 - 16, +                            }); +                            prefixes.set_fs(); +                        }, +                        0x65 => { +                            sink.record((words.offset() - 2) as u32 * 8, (words.offset() - 2) as u32 * 8 + 7, FieldDescription { +                                desc: InnerDescription::SegmentPrefix(Segment::GS), +                                id: words.offset() as u32 * 8 - 16, +                            }); +                            prefixes.set_gs(); +                        }, +                        0xf0 => { +                            sink.record((words.offset() - 2) as u32 * 8, (words.offset() - 2) as u32 * 8 + 7, FieldDescription { +                                desc: InnerDescription::Misc("lock prefix"), +                                id: words.offset() as u32 * 8 - 16, +                            }); +                            prefixes.set_lock(); +                        }, +                        _ => { return read_avx_prefixed(b, words, instruction, sink); } +                    } +                } +                nextb = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; +                next_rec = unsafe { +                    core::ptr::read_volatile(&OPCODES[nextb as usize]) +                }; +                if prefixes.rex.bits != 0 { +                    sink.record((words.offset() - 2) as u32 * 8, (words.offset() - 2) as u32 * 8 + 7, FieldDescription { +                        desc: InnerDescription::Misc("invalidates prior rex prefix"), +                        id: (words.offset() as u32 * 8 - 16) + 1, +                    }); +                } +                prefixes.rex_from(0); +            } +            if words.offset() >= 15 { +                return Err(DecodeError::TooLong);              } +        }; + +        if let Interpretation::Instruction(opcode) = record.0 { +            instruction.opcode = opcode; +        } else { +            unsafe { unreachable_unchecked(); }          } + +        record.1      }; -    if let Interpretation::Instruction(opcode) = record.0 { -        instruction.opcode = opcode; -    } else { -        unsafe { unreachable_unchecked(); } -    } -    instruction.prefixes = prefixes; -    read_operands(decoder, words, instruction, record.1, sink)?; +    read_operands(decoder, words, instruction, record, sink)?;      if instruction.prefixes.lock() {          if !LOCKABLE_INSTRUCTIONS.contains(&instruction.opcode) || !instruction.operands[0].is_memory() { @@ -6645,6 +6585,61 @@ fn read_with_annotations<      Ok(())  } +#[inline(never)] +fn read_avx_prefixed< +    T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>, +    S: DescriptionSink<FieldDescription>, +>(b: u8, words: &mut T, instruction: &mut Instruction, sink: &mut S) -> Result<(), DecodeError> { +    if instruction.prefixes.rex_unchecked().present() || instruction.prefixes.lock() || instruction.prefixes.operand_size() || instruction.prefixes.rep() || instruction.prefixes.repnz() { +        // rex and then vex is invalid! reject it. +        return Err(DecodeError::InvalidPrefixes); +    } +    instruction.mem_size = 0; +    instruction.operand_count = 2; + +    // some prefix seen after we saw rex, but before the 0f escape or an actual +    // opcode. so we must forget the rex prefix! +    // this is to handle sequences like 41660f21cf +    // where if 660f21 were a valid opcode, 41 would apply a rex.b +    // prefix, but since 660f21 is not valid, the opcode is interpreted +    // as 0f21, where 66 is a prefix, which makes 41 not the last +    // prefix before the opcode, and it's discarded. + +    // 2.3.2 +    // Any VEX-encoded instruction with a LOCK prefix preceding VEX will #UD. +    // 2.3.3 +    // Any VEX-encoded instruction with a 66H, F2H, or F3H prefix preceding VEX +    // will #UD. +    // 2.3.4 +    // Any VEX-encoded instruction with a REX prefix proceeding VEX will #UD. +    if b == 0xc5 { +        sink.record( +            words.offset() as u32 * 8 - 8, +            words.offset() as u32 * 8 - 1, +            InnerDescription::Misc("two-byte vex prefix (0xc5)") +                .with_id(words.offset() as u32 * 8 - 8) +        ); +        vex::two_byte_vex(words, instruction, sink)?; +    } else if b == 0xc4 { +        sink.record( +            words.offset() as u32 * 8 - 8, +            words.offset() as u32 * 8 - 1, +            InnerDescription::Misc("three-byte vex prefix (0xc4)") +                .with_id(words.offset() as u32 * 8 - 8) +        ); +        vex::three_byte_vex(words, instruction, sink)?; +    } else if b == 0x62 { +        sink.record( +            words.offset() as u32 * 8 - 8, +            words.offset() as u32 * 8 - 1, +            InnerDescription::Misc("evex prefix (0x62)") +                .with_id(words.offset() as u32 * 8 - 8) +        ); +        evex::read_evex(words, instruction, None, sink)?; +    } +    return Ok(()); +} +  /* likely cases          OperandCode::Eb_R0 => 0          _op @ OperandCode::ModRM_0x80_Eb_Ib => 1  | 
