1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use std::io::Read;
use crate::bitfields::Position;
use crate::isa::*;
use crate::opcode::{self, OperandSize};
use crate::operands::Operand;
use crate::{FalconError, Instruction};
mod pretty;
pub use pretty::Disassembler;
pub fn read_instruction<R: Read>(reader: &mut R, pc: &mut u32) -> Result<Instruction, FalconError> {
let mut insn = Vec::new();
let opcode = {
read_bytes(&mut insn, reader, 1)?;
insn[0]
};
let (a, b) = opcode::get_opcode_form(opcode);
let operand_size = OperandSize::from(opcode);
let subopcode = {
let location = opcode::get_subopcode_location(operand_size.value(), a, b)
.ok_or(FalconError::InvalidOpcode(opcode))?;
let bf = location.field();
read_bytes(&mut insn, reader, bf.position().0 as u64)?;
bf.read(&insn)
};
Ok({
let mut meta = InstructionKind::lookup_meta(operand_size.sized(), a, b, subopcode)
.ok_or(FalconError::InvalidOpcode(opcode))?;
let operands = read_operands(&mut insn, reader, &mut meta, operand_size.value(), *pc)?;
let instruction = Instruction::new(meta, operand_size, operands, *pc, insn);
*pc += instruction.raw_bytes().len() as u32;
instruction
})
}
fn read_operands<R: Read>(
buf: &mut Vec<u8>,
reader: &mut R,
meta: &mut InstructionMeta,
operand_size: u8,
pc: u32,
) -> Result<Vec<Operand>, FalconError> {
let mut result = Vec::new();
for dispatch in meta.operands.iter_mut().flatten() {
let encoding = dispatch.evaluate(operand_size);
let mut bytes_to_read = 0;
let operand_width = {
let (start, nbytes) = encoding.position();
start + nbytes
};
if buf.len() < operand_width {
bytes_to_read += (operand_width - buf.len()) as u64;
}
read_bytes(buf, reader, bytes_to_read)?;
result.push(encoding.read(pc, buf));
}
Ok(result)
}
fn read_bytes<R: Read>(
buf: &mut Vec<u8>,
reader: &mut R,
amount: u64,
) -> Result<usize, FalconError> {
match reader.take(amount).read_to_end(buf) {
Ok(0) if amount != 0 => Err(FalconError::Eof),
Ok(nbytes) => Ok(nbytes),
Err(e) => Err(FalconError::IoError(e)),
}
}