aboutsummaryrefslogtreecommitdiff
path: root/src/real_mode/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/real_mode/mod.rs')
-rw-r--r--src/real_mode/mod.rs88
1 files changed, 88 insertions, 0 deletions
diff --git a/src/real_mode/mod.rs b/src/real_mode/mod.rs
index 709a301..42a0b03 100644
--- a/src/real_mode/mod.rs
+++ b/src/real_mode/mod.rs
@@ -2702,6 +2702,78 @@ impl LengthedInstruction for Instruction {
}
}
+#[cfg(feature="_debug_internal_disasm_stats")]
+mod disasm_stats {
+ macro_rules! shim_impl {
+ ($name:ident) => {
+ #[inline(always)]
+ pub fn $name() { }
+ }
+ }
+
+ #[inline(always)]
+ pub fn record_opcode(_opc: super::Opcode) {
+ }
+
+ #[inline(always)]
+ pub(crate) fn record_operand_case(_oper: super::OperandCase) {
+ }
+
+ shim_impl!(record_opc_0f);
+ shim_impl!(record_opc_rep_0f);
+ shim_impl!(record_opc_repnz_0f);
+ shim_impl!(record_opc_op_size_0f);
+ shim_impl!(record_opc_0f38);
+ shim_impl!(record_opc_0f3a);
+
+ shim_impl!(check_lock);
+ shim_impl!(read_operands);
+ shim_impl!(is_only_modrm_operands);
+ shim_impl!(instr_done);
+
+ shim_impl!(read_opc_hotpath_hit);
+ shim_impl!(read_opc_hotpath_miss);
+ shim_impl!(indirect_branch_prefixes_slow);
+}
+#[cfg(not(feature="_debug_internal_disasm_stats"))]
+mod disasm_stats {
+ macro_rules! shim_impl {
+ ($name:ident) => {
+ #[inline(always)]
+ pub fn $name() { }
+ }
+ }
+
+ #[inline(always)]
+ pub fn record_opcode(_opc: super::Opcode) {
+ }
+
+ #[inline(always)]
+ pub(crate) fn record_operand_case(_oper: super::OperandCase) {
+ }
+
+ shim_impl!(record_opc_0f);
+ shim_impl!(record_opc_rep_0f);
+ shim_impl!(record_opc_repnz_0f);
+ shim_impl!(record_opc_op_size_0f);
+ shim_impl!(record_opc_0f38);
+ shim_impl!(record_opc_0f3a);
+
+ shim_impl!(check_lock);
+ shim_impl!(read_operands);
+ shim_impl!(is_only_modrm_operands);
+ shim_impl!(instr_done);
+
+ shim_impl!(read_opc_hotpath_hit);
+ shim_impl!(read_opc_hotpath_miss);
+ shim_impl!(indirect_branch_prefixes_slow);
+}
+
+#[cfg(feature="_debug_internal_disasm_stats")]
+pub use disasm_stats::DisasmStats;
+#[cfg(feature="_debug_internal_disasm_stats")]
+pub use disasm_stats::DISASM_STATS;
+
/// an `x86` instruction decoder.
///
/// fundamentally this is one or two primitives with no additional state kept during decoding. it
@@ -5286,6 +5358,7 @@ fn record_opcode_record_found<
T: Reader<Address<Arch>, Word<Arch>>,
S: DescriptionSink<FieldDescription>,
>(words: &mut T, sink: &mut S, opc: Opcode, code: OperandCode, opc_length: u32) {
+ disasm_stats::record_opcode(opc);
let offset = words.offset() as u32;
let opcode_start_bit = (offset - opc_length) * 8;
let opcode_end_bit = offset * 8 - 1;
@@ -5393,8 +5466,10 @@ fn read_with_annotations<
instruction.regs[2] = RegSpec::ax();
let record: OperandCode = if self.read_opc_hotpath(nextb, &mut nextb, &mut next_rec, words, instruction, sink)? {
+ disasm_stats::read_opc_hotpath_hit();
next_rec.operand()
} else {
+ disasm_stats::read_opc_hotpath_miss();
let prefixes = &mut instruction.prefixes;
let record = loop {
let record = next_rec;
@@ -5451,6 +5526,7 @@ fn read_with_annotations<
});
prefixes.set_rep();
} else {
+ disasm_stats::indirect_branch_prefixes_slow();
match b {
0x26 => {
sink.record((words.offset() - 1) as u32 * 8, (words.offset() - 1) as u32 * 8 + 7, FieldDescription {
@@ -5528,11 +5604,14 @@ fn read_with_annotations<
self.read_operands(decoder, words, instruction, record, sink)?;
if self.check_lock {
+ disasm_stats::check_lock();
if !instruction.opcode.can_lock() || !instruction.operands[0].is_memory() {
return Err(DecodeError::InvalidPrefixes);
}
}
+ disasm_stats::instr_done();
+
Ok(())
}
@@ -5542,6 +5621,7 @@ fn read_operands<
T: Reader<Address<Arch>, Word<Arch>>,
S: DescriptionSink<FieldDescription>
>(&mut self, decoder: &InstDecoder, words: &mut T, instruction: &mut Instruction, operand_code: OperandCode, sink: &mut S) -> Result<(), DecodeError> {
+ disasm_stats::read_operands();
sink.record(
words.offset() as u32 * 8 - 1, words.offset() as u32 * 8 - 1,
InnerDescription::Boundary("opcode ends/operands begin (typically)")
@@ -5552,6 +5632,7 @@ fn read_operands<
let opcode_start = modrm_start - 8;
if operand_code.is_only_modrm_operands() {
+ disasm_stats::is_only_modrm_operands();
let bank;
// cool! we can precompute width and know we need to read_E.
if !operand_code.has_byte_operands() {
@@ -5818,6 +5899,7 @@ fn read_operands<
}
instruction.operand_count = 2;
+ disasm_stats::record_operand_case(operand_code.operand_case_handler_index());
// match operand_code {
match operand_code.operand_case_handler_index() {
// these operand cases are all `only_*`, and are unreachable here..
@@ -8888,17 +8970,22 @@ fn read_0f_opcode(&mut self, opcode: u8, prefixes: &mut Prefixes) -> OpcodeRecor
// invalid prefix is in fact an invalid instruction. so just duplicate for the four kinds of
// opcode lists.
if prefixes.repnz() {
+ disasm_stats::record_opc_repnz_0f();
REPNZ_0F_CODES[opcode as usize]
} else if prefixes.rep() {
+ disasm_stats::record_opc_rep_0f();
REP_0F_CODES[opcode as usize]
} else if prefixes.operand_size() {
+ disasm_stats::record_opc_op_size_0f();
OPERAND_SIZE_0F_CODES[opcode as usize]
} else {
+ disasm_stats::record_opc_0f();
NORMAL_0F_CODES[opcode as usize]
}
}
fn read_0f38_opcode(&mut self, opcode: u8, prefixes: &mut Prefixes) -> OpcodeRecord {
+ disasm_stats::record_opc_0f38();
if prefixes.rep() {
return match opcode {
0xd8 => OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf30f38d8),
@@ -9031,6 +9118,7 @@ fn read_0f38_opcode(&mut self, opcode: u8, prefixes: &mut Prefixes) -> OpcodeRec
}
fn read_0f3a_opcode(&mut self, opcode: u8, prefixes: &mut Prefixes) -> OpcodeRecord {
+ disasm_stats::record_opc_0f3a();
if prefixes.rep() {
if prefixes != &Prefixes::new(0x10) {
return OpcodeRecord::new(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing);