Updates Rust binding to the latest version.

Fixed build in disasmtool_lix.
pull/54/head v1.34.10
BITDEFENDER\vlutas 2 years ago
parent fe6a937f51
commit 70db095765

@ -0,0 +1,7 @@
# bddisasm-sys changelog
## Unreleased
### Changed
- the crate is now a `no_std` crate (this adds a dependency on [cty](https://crates.io/crates/cty))

@ -1,6 +1,6 @@
[package]
name = "bddisasm-sys"
version = "0.1.0"
version = "0.1.1"
authors = ["Cristi Anichitei <ianichitei@bitdefender.com>"]
edition = "2018"
links = "bddisasm"
@ -12,7 +12,7 @@ documentation = "https://docs.rs/bddisasm-sys"
description = """
Bindings to bddisasm instruction decoder library
"""
categories = ["external-ffi-bindings", "hardware-support"]
categories = ["external-ffi-bindings", "hardware-support", "no_std"]
keywords = ["disassembler", "decoder", "x86", "amd64", "x86_64"]
[lib]
@ -20,6 +20,7 @@ name = "bddisasm_sys"
path = "src/lib.rs"
[dependencies]
cty = "0.2.2"
[build-dependencies]
bindgen = "0.59.1"

@ -1,9 +1,13 @@
# bddisasm-sys
Rust bindings for [bddisasm](https://github.com/bitdefender/bddisasm).
`no_std` Rust bindings for [bddisasm](https://github.com/bitdefender/bddisasm).
See [bddisasm](https://crates.io/crates/bddisasm) if you're looking for a Rust wrapper for these bindings.
## Requirements
[bindgen](https://crates.io/crates/bindgen) is used to generate the bindings at build time. Because of this, users need to have `clang` installed. Check the [bindgen documentation](https://rust-lang.github.io/rust-bindgen/requirements.html) for more information.
## Notes
While this crate is `no_std`, the `bddisasm` library it links against depends on a C library because it needs `vsnprintf` and `memset`. It is possible to [work around this limitation](https://github.com/bitdefender/bddisasm#nd_vsnprintf_s-and-nd_memset), but this is not currently done for these bindings.

@ -11,6 +11,7 @@ fn main() {
cc::Build::new()
.file("csrc/bddisasm/bddisasm.c")
.file("csrc/bddisasm/bdformat.c")
.file("csrc/bddisasm/bdhelpers.c")
.file("csrc/bddisasm/crt.c")
.include("csrc/bddisasm/include")
.include("csrc/inc")
@ -24,6 +25,8 @@ fn main() {
.allowlist_type("ND.*")
.allowlist_var("ND.*")
.rustified_enum(".*")
.ctypes_prefix("cty")
.use_core()
.impl_debug(true)
.generate_comments(false)
.parse_callbacks(Box::new(bindgen::CargoCallbacks))

@ -11,6 +11,7 @@
//! [bindgen](https://crates.io/crates/bindgen) is used to generate the bindings at build time. Because of this, users
//! need to have `clang` installed.
//! Check the [bindgen documentation](https://rust-lang.github.io/rust-bindgen/requirements.html) for more information.
#![cfg_attr(not(test), no_std)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]

@ -0,0 +1,17 @@
# bddisasm changelog
## Unreleased
### Added
- implement `Decoder::decode_next_with_offset`
- implement ``Decoder::decode_next_with_ip`
- `OperandLookup` struct which makes working with operands easier
- re-export `bddisasm_sys` as `ffi`
- re-export commonly used items
- Implement `as_*` and `is_*` accessors for the `OpInfo` enum
### Changed
- the crate is now a `no_std` crate
- public types no longer implement `From` and no longer `panic!` when an unexpected value is encountered

@ -1,6 +1,6 @@
[package]
name = "bddisasm"
version = "0.1.0"
version = "0.1.2"
authors = ["Cristi Anichitei <ianichitei@bitdefender.com>"]
edition = "2018"
license = "Apache-2.0"
@ -15,3 +15,13 @@ keywords = ["disassembler", "decoder", "x86", "amd64", "x86_64"]
[dependencies]
bddisasm-sys = { version = "0.1.0", path = "../bddisasm-sys" }
[features]
std = []
[package.metadata."docs.rs"]
all-features = true
[dev-dependencies]
anyhow = "1.0"
clap = "2.34.0"

@ -1,11 +1,13 @@
# bddisasm
# bddisasm x86/x64 instruction decoder
Rust bindings for the [bddisasm](https://github.com/bitdefender/bddisasm) x86/x64 decoder library, built on top
of [bddisasm-sys](https://crates.io/crates/bddisasm-sys).
`no_std` Rust bindings for the [bddisasm](https://github.com/bitdefender/bddisasm) x86/x64 decoder library, built
on top of [bddisasm-sys](https://crates.io/crates/bddisasm-sys).
It supports all existing x86 instruction, offering a wide range of information about each one, including:
It supports all existing 16-bit, 32-bit and 64-bit instructions, offering a wide range of information about each one,
including:
- operands (implicit and explicit)
- implicit operands
- explicit operands
- access mode for each operand
- CPUID feature flags
- CPU modes in which an instruction is valid
@ -23,8 +25,11 @@ bddisasm = "0.1.0"
### Decoding one instruction
```rust
use bddisasm::decoded_instruction::{DecodedInstruction, DecodeMode, Mnemonic};
Use [`DecodedInstruction::decode`](https://docs.rs/bddisasm/latest/bddisasm/decoded_instruction/struct.DecodedInstruction.html#method.decode)
to decode an instruction from a chunk of code.
```Rust
use bddisasm::{DecodedInstruction, DecodeMode, Mnemonic};
let code = vec![0x31, 0xc0];
match DecodedInstruction::decode(&code, DecodeMode::Bits32) {
@ -38,8 +43,11 @@ match DecodedInstruction::decode(&code, DecodeMode::Bits32) {
### Decoding multiple instructions
```rust
use bddisasm::decoder::{Decoder, DecodeMode};
Use [`Decoder`](https://docs.rs/bddisasm/latest/bddisasm/decoder/struct.Decoder.html) to decode multiple instructions
from a chunk of code.
```Rust
use bddisasm::{Decoder, DecodeMode};
let code = [
// ENCLS
@ -70,21 +78,58 @@ the provided input buffer is too small
WRMSR
```
Use [`Decoder::decode_next_with_info`](https://docs.rs/bddisasm/latest/bddisasm/decoder/struct.Decoder.html#method.decode_next_with_info)
to get information about the offset inside the code chunk at which an instruction was decoded from.
```Rust
use bddisasm::{Decoder, DecodeMode};
let code = [
// ENCLS
0x0f, 0x01, 0xcf,
// MOV rax, qword ptr [rbx+rcx*4+0x1234]
0x48, 0x8b, 0x84, 0x8b, 0x34, 0x12, 0x00, 0x00,
// Not a valid instruction
0x0f,
// WRMSR
0x0f, 0x30,
];
let mut decoder = Decoder::new(&code, DecodeMode::Bits64, 0x1234);
// Keep decoding until there's nothing left to decode
while let Some((result, offset, _)) = decoder.decode_next_with_info() {
match result {
Ok(ins) => println!("{:#x} {}", offset, ins),
Err(e) => println!("Error: `{}` at offset {:#x}", e, offset),
}
}
```
This will print:
```text
0x0 ENCLS
0x3 MOV rax, qword ptr [rbx+rcx*4+0x1234]
Error `the provided input buffer is too small` at offset 0xb
0xc WRMSR
```
### Working with instruction operands
Rich informaion is offered for each type of operand. Bellow is a minimal example that looks at a memory operand.
Instruction operands can be analyzed using the [operand](https://docs.rs/bddisasm/latest/bddisasm/operand/index.html)
module. Rich informaion is offered for each type of operand. Bellow is a minimal example that looks at a memory operand.
```rust
# use bddisasm::decode_error::DecodeError;
# fn test() -> Result<(), DecodeError> {
use bddisasm::decoded_instruction::{DecodedInstruction, DecodeMode};
use bddisasm::operand::OpInfo;
```Rust
use bddisasm::{DecodedInstruction, DecodeMode, OpInfo};
// ` MOV rax, qword ptr [rcx+r15*2]`
let code = b"\x4a\x8b\x04\x79";
let ins = DecodedInstruction::decode(code, DecodeMode::Bits64).unwrap();
// Get the operands
let operands = ins.operands();
// Get the second operand which is the source (`[rcx+r15*2]`)
let src = operands[1];
@ -117,8 +162,6 @@ match src.info {
},
_ => unreachable!(),
}
# Ok(())
# }
```
Will print:
@ -131,6 +174,11 @@ Scale: 2
No displacement
```
## Requirements
## Accessing the raw bindings
The raw `bddisasm_sys` bindings are available via the `ffi` re-export.
## Feature Flags
Because [bddisasm-sys](https://crates.io/crates/bddisasm-sys) uses [bindgen](https://crates.io/crates/bindgen) to generate the bindings at build time, users need to have `clang` installed. Check the [bindgen documentation](https://rust-lang.github.io/rust-bindgen/requirements.html) for more information.
- `std` - adds a `std` dependency - the only visible difference when doing this is that [`DecodeError`] implements
the `Error` trait

@ -0,0 +1,159 @@
extern crate bddisasm;
use std::fmt;
use bddisasm::{DecodeMode, DecodedInstruction, Decoder, Mnemonic, OpRegType, Operand};
use anyhow::Result;
use clap::{App, Arg};
static ABOUT: &str = "
Simple emulator example.
Supports only a few 64-bit instructions (MOV, INC, DEC) and operand types (register, and immediate).
All registers are initially set to 0.
";
/// Holds the reigster state.
#[derive(Debug, Default)]
struct Context {
/// Registers are in the Intel documented order (RAX, RCX, RDX, etc).
regs: [u64; 16],
}
impl Context {
/// Emulates a 64-bit instruction.
pub fn emulate(&mut self, ins: &DecodedInstruction) -> Result<()> {
let operands = ins.operands();
match ins.mnemonic() {
Mnemonic::Mov => {
self.set_operand_value(&operands[0], self.get_operand_value(&operands[1])?)?
}
Mnemonic::Inc => self.set_operand_value(
&operands[0],
self.get_operand_value(&operands[0])?.wrapping_add(1),
)?,
Mnemonic::Dec => self.set_operand_value(
&operands[0],
self.get_operand_value(&operands[0])?.wrapping_sub(1),
)?,
_ => anyhow::bail!("Unsupported instruction: {}", ins),
}
Ok(())
}
fn get_operand_value(&self, op: &Operand) -> Result<u64> {
if let Some(reg) = op.info.as_reg() {
if reg.kind != OpRegType::Gpr {
anyhow::bail!("Unsupported register type: {}", reg.kind)
} else {
match reg.size {
1 => {
if reg.is_high8 {
// For `AH`, `BH`, etc.
Ok((self.regs[reg.index] & 0xFF00) >> 8)
} else {
Ok(self.regs[reg.index] & 0xFF)
}
}
2 => Ok(self.regs[reg.index] & 0xFFFF),
4 => Ok(self.regs[reg.index] & 0xFFFFFFFF),
8 => Ok(self.regs[reg.index]),
_ => unreachable!("Unexpected GPR size: {}", reg.size),
}
}
} else if let Some(imm) = op.info.as_imm() {
Ok(imm)
} else {
anyhow::bail!("Unsupported operand type: {}", op.info)
}
}
fn set_operand_value(&mut self, op: &Operand, value: u64) -> Result<()> {
if let Some(reg) = op.info.as_reg() {
if reg.kind != OpRegType::Gpr {
anyhow::bail!("Unsupported register type: {}", reg.kind)
} else {
let orig_value = self.regs[reg.index];
let value = match reg.size {
1 => {
if reg.is_high8 {
let value = value << 8;
value | (orig_value & 0xFFFFFFFFFFFF00FF)
} else {
value | (orig_value & 0xFFFFFFFFFFFFFF00)
}
}
2 => value | (orig_value & 0xFFFFFFFFFFFF0000),
4 => {
// The upper 32-bits are always set to 0.
value & 0xFFFFFFFF
}
8 => value,
_ => unreachable!("Unexpected GPR size: {}", reg.size),
};
self.regs[reg.index] = value;
Ok(())
}
} else {
anyhow::bail!("Unsupported operand type: {}", op.info)
}
}
}
impl fmt::Display for Context {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let names = [
"RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI", " R8", " R9", "R10", "R11",
"R12", "R13", "R14", "R15",
];
for (i, name) in names.iter().enumerate() {
if let Err(e) = write!(f, "{}: {:#018x} ", name, self.regs[i]) {
return Err(e);
}
if (i + 1) % 4 == 0 {
if let Err(e) = writeln!(f) {
return Err(e);
}
}
}
Ok(())
}
}
fn main() -> Result<()> {
let matches = App::new("emulator")
.about(ABOUT)
.arg(
Arg::with_name("INPUT")
.short("f")
.long("file")
.value_name("PATH")
.help("Path to the binary file from which to load code")
.takes_value(true),
)
.get_matches();
let code = std::fs::read(matches.value_of("INPUT").unwrap())?;
let decoder = Decoder::new(&code, DecodeMode::Bits64, 0);
let mut ctx = Context::default();
for ins in decoder {
match ins {
Ok(ins) => {
ctx.emulate(&ins)?;
println!("{}\n{}", ins, ctx);
}
Err(e) => anyhow::bail!("Failed to decode: {}", e),
}
}
Ok(())
}

@ -7,10 +7,10 @@
//! # Examples
//!
//! ```
//! # use std::error::Error;
//! # use bddisasm::DecodeError;
//! #
//! # fn main() -> Result<(), Box<dyn Error>> {
//! use bddisasm::decoded_instruction::{DecodedInstruction, DecodeMode, Mnemonic, OperandSize};
//! # fn main() -> Result<(), DecodeError> {
//! use bddisasm::{DecodedInstruction, DecodeMode, Mnemonic};
//!
//! // `VMXON qword ptr [rax]`
//! let ins = DecodedInstruction::decode(&[0xf3, 0x0f, 0xc7, 0x30], DecodeMode::Bits64)?;
@ -26,16 +26,21 @@
//! # Ok(())
//! # }
extern crate bddisasm_sys as ffi;
// TODO: maybe use something like the `bitflags` crate and have all these as flags?
/// Privilege levels (rings) in which an instruction is supported.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct PrivilegeLevel {
/// Instruction is valid in ring 0.
pub ring0: bool,
/// Instruction is valid in ring 1.
pub ring1: bool,
/// Instruction is valid in ring 2.
pub ring2: bool,
/// Instruction is valid in ring 3.
pub ring3: bool,
}
@ -109,11 +114,11 @@ pub struct CpuModes {
}
#[doc(hidden)]
impl From<ffi::ND_VALID_MODES> for CpuModes {
fn from(raw: ffi::ND_VALID_MODES) -> CpuModes {
impl CpuModes {
pub(crate) fn from_raw(raw: ffi::ND_VALID_MODES) -> Self {
let raw = unsafe { raw.__bindgen_anon_1 };
CpuModes {
Self {
privilege_level: PrivilegeLevel {
ring0: raw.Ring0() != 0,
ring1: raw.Ring1() != 0,

@ -7,10 +7,10 @@
//! # Examples
//!
//! ```
//! # use std::error::Error;
//! # use bddisasm::DecodeError;
//! #
//! # fn test() -> Option<()> {
//! use bddisasm::decoded_instruction::{DecodedInstruction, DecodeMode};
//! use bddisasm::{DecodedInstruction, DecodeMode};
//!
//! // `ENCLS`
//! let ins = DecodedInstruction::decode(&[0x0f, 0x01, 0xcf], DecodeMode::Bits64).ok()?;
@ -25,9 +25,7 @@
//! # Some(())
//! # }
extern crate bddisasm_sys as ffi;
use std::fmt;
use core::fmt;
/// Describes the CPUID leaf, sub-leaf, register & bit that indicate whether an instruction is supported or not.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]

@ -7,36 +7,20 @@
//!
//! # Notes
//!
//! All error codes that can be returned by `bddisasm-sys` are encapsulated in the [DecodeError](DecodeError) enum.
//! All error codes that can be returned by `bddisasm-sys` are encapsulated in the [`DecodeError`](DecodeError) enum.
//! However, some of these are unlikely to be encountered when using this crate (for example,
//! [BufferOverflow](DecodeError::BufferOverflow)) which indicates that a buffer passed to the `bddisasm` C library is
//! [`BufferOverflow`](DecodeError::BufferOverflow)) which indicates that a buffer passed to the `bddisasm` C library is
//! not large enough.
//!
//! Other errors, such as [UnknownStatus](DecodeError::UnknownStatus) or
//! [UnknownInstruction](DecodeError::UnknownInstruction) are used to indicate that this crate is out of sync with
//! `bddisasm-sys`, which also should never happen.
extern crate bddisasm_sys as ffi;
use std::error::Error;
use std::fmt;
use core::fmt;
/// Holds all the possible errors that can be encountered by the decoder.
///
/// # Notes
///
/// If the `std` feature is disabled, [`DecodeError`] does not implement the `Error` trait.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum DecodeError {
/// The underlying bddisasm status is not known. The inner value holds the status as it was returned by bddisasm.
///
/// This usually means that this library is out of sync with bddisasm-sys and is not aware that a new error status
/// was added.
UnknownStatus(u32),
/// The instruction class returned by bddisasm is not known. The inner value holds the instruction class as it was
/// returned by bddisasm.
///
/// This usually means that this library is out of sync with bddisasm-sys and is not aware that a new instruction
/// class was added.
UnknownInstruction(u32),
/// The provided input buffer is too small and does not contain a valid instruction.
BufferTooSmall,
@ -134,16 +118,12 @@ pub enum DecodeError {
BufferOverflow,
/// Internal library error.
InternalError,
InternalError(u64),
}
impl fmt::Display for DecodeError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
DecodeError::UnknownStatus(value) => write!(f, "unknown status: {:#x}", value),
DecodeError::UnknownInstruction(value) => {
write!(f, "unknown instruction: {:#x}", value)
}
DecodeError::BufferTooSmall => write!(f, "the provided input buffer is too small"),
DecodeError::InvalidEncoding => write!(f, "invalid encoding/instruction"),
DecodeError::InstructionTooLong => {
@ -156,7 +136,9 @@ impl fmt::Display for DecodeError {
DecodeError::XopWithPrefix => write!(f, "XOP is present, but also a legacy prefix"),
DecodeError::VexWithPrefix => write!(f, "VEX is present, but also a legacy prefix"),
DecodeError::EvexWithPrefix => write!(f, "EVEX is present, but also a legacy prefix"),
DecodeError::InvalidEncodingInMode => write!(f, "invalid encoding/instruction"),
DecodeError::InvalidEncodingInMode => {
write!(f, "invalid encoding/instruction in the given mode")
}
DecodeError::BadLockPrefix => write!(f, "invalid usage of LOCK"),
DecodeError::CsLoad => write!(f, "an attempt to load the CS register"),
DecodeError::Prefix66NotAccepted => write!(f, "0x66 prefix is not accepted"),
@ -199,12 +181,13 @@ impl fmt::Display for DecodeError {
DecodeError::BufferOverflow => {
write!(f, "not enough space is available to format instruction")
}
DecodeError::InternalError => write!(f, "internal error"),
DecodeError::InternalError(e) => write!(f, "internal error: {}", e),
}
}
}
impl Error for DecodeError {}
#[cfg(feature = "std")]
impl std::error::Error for DecodeError {}
pub(crate) fn status_to_error(status: ffi::NDSTATUS) -> Result<(), DecodeError> {
if status == ffi::ND_STATUS_SUCCESS || status == ffi::ND_STATUS_HINT_OPERAND_NOT_USED {
@ -249,8 +232,8 @@ pub(crate) fn status_to_error(status: ffi::NDSTATUS) -> Result<(), DecodeError>
ffi::ND_STATUS_INVALID_PARAMETER => Err(DecodeError::InvalidParameter),
ffi::ND_STATUS_INVALID_INSTRUX => Err(DecodeError::InvalidInstrux),
ffi::ND_STATUS_BUFFER_OVERFLOW => Err(DecodeError::BufferOverflow),
ffi::ND_STATUS_INTERNAL_ERROR => Err(DecodeError::InternalError),
_ => Err(DecodeError::UnknownStatus(status)),
ffi::ND_STATUS_INTERNAL_ERROR => Err(DecodeError::InternalError(0)),
_ => panic!("Unexpected status: {:#x}", status),
}
}
}

File diff suppressed because it is too large Load Diff

@ -4,14 +4,10 @@
*/
//! Decodes instructions.
extern crate bddisasm_sys as ffi;
pub use crate::decode_error::DecodeError;
pub use crate::decoded_instruction::{DecodeMode, DecodeResult, DecodedInstruction};
pub use crate::mnemonic::Mnemonic;
use crate::decoded_instruction::{DecodeMode, DecodeResult, DecodedInstruction};
/// Decodes instructions.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct Decoder<'a> {
code: &'a [u8],
ip: u64,
@ -61,10 +57,10 @@ impl<'a> Decoder<'a> {
/// # Examples
///
/// ```
/// # use std::error::Error;
/// # use bddisasm::DecodeError;
/// #
/// # fn main() -> Result<(), Box<dyn Error>> {
/// use bddisasm::decoder::{Decoder, DecodeMode};
/// # fn main() -> Result<(), DecodeError> {
/// use bddisasm::{Decoder, DecodeMode};
///
/// let mut decoder = Decoder::new(&[0x51, 0x53], DecodeMode::Bits32, 0);
///
@ -103,16 +99,16 @@ impl<'a> Decoder<'a> {
/// Attempts to decode the next instruction from the given code chunk.
///
/// Behaves like [decode_next](Decoder::decode_next), but in addition to the [DecodeResult](DecodeResult) it will
/// also return the offset from which decoding was attempted, as well as the corresponding instruction pointer.
/// Behaves like [`decode_next`](Decoder::decode_next), but in addition to the [`DecodeResult`](DecodeResult) it
/// will also return the offset from which decoding was attempted, as well as the corresponding instruction pointer.
///
/// # Examples
///
/// ```
/// # use std::error::Error;
/// # use bddisasm::DecodeError;
/// #
/// # fn main() -> Result<(), Box<dyn Error>> {
/// use bddisasm::decoder::{Decoder, DecodeMode};
/// # fn main() -> Result<(), DecodeError> {
/// use bddisasm::{Decoder, DecodeMode};
///
/// let mut decoder = Decoder::new(&[0x51, 0x53], DecodeMode::Bits32, 0x1000);
///
@ -128,12 +124,81 @@ impl<'a> Decoder<'a> {
/// # Ok(())
/// # }
/// ```
#[inline]
pub fn decode_next_with_info(&mut self) -> Option<(DecodeResult, usize, u64)> {
let offset = self.offset;
let ip = self.ip;
self.decode_next().map(|res| (res, offset, ip))
}
/// Attempts to decode the next instruction from the given code chunk.
///
/// Behaves like [`decode_next`](Decoder::decode_next), but in addition to the [`DecodeResult`](DecodeResult) it
/// will also return the offset from which decoding was attempted.
///
/// # Examples
///
/// ```
/// # use bddisasm::DecodeError;
/// #
/// # fn main() -> Result<(), DecodeError> {
/// use bddisasm::{Decoder, DecodeMode};
///
/// let mut decoder = Decoder::new(&[0x51, 0x53], DecodeMode::Bits32, 0x1000);
///
/// // As long as we have something to decode
/// while let Some((result, offset)) = decoder.decode_next_with_offset() {
/// // Check if the decoding succeeded
/// match result {
/// Ok(instruction) => println!("{} at offset {:#x}", instruction, offset),
/// Err(e) => println!("Unable to decode at offset {:#x}: {}", offset, e),
/// }
/// }
///
/// # Ok(())
/// # }
/// ```
#[inline]
pub fn decode_next_with_offset(&mut self) -> Option<(DecodeResult, usize)> {
let offset = self.offset;
self.decode_next().map(|res| (res, offset))
}
/// Attempts to decode the next instruction from the given code chunk.
///
/// Behaves like [`decode_next`](Decoder::decode_next), but in addition to the [`DecodeResult`](DecodeResult) it
/// will also return the corresponding instruction pointer.
///
/// # Examples
///
/// ```
/// # use bddisasm::DecodeError;
/// #
/// # fn main() -> Result<(), DecodeError> {
/// use bddisasm::{Decoder, DecodeMode};
///
/// let mut decoder = Decoder::new(&[0x51, 0x53], DecodeMode::Bits32, 0x1000);
///
/// // As long as we have something to decode
/// while let Some((result, ip)) = decoder.decode_next_with_ip() {
/// // Check if the decoding succeeded
/// match result {
/// Ok(instruction) => println!("{:#x} {}", ip, instruction),
/// Err(e) => println!("Unable to decode: {}", e),
/// }
/// }
///
/// # Ok(())
/// # }
/// ```
#[inline]
pub fn decode_next_with_ip(&mut self) -> Option<(DecodeResult, u64)> {
let ip = self.ip;
self.decode_next().map(|res| (res, ip))
}
}
impl Iterator for Decoder<'_> {
@ -145,11 +210,12 @@ impl Iterator for Decoder<'_> {
}
}
impl std::iter::FusedIterator for Decoder<'_> {}
impl core::iter::FusedIterator for Decoder<'_> {}
#[cfg(test)]
mod tests {
use super::*;
use crate::*;
#[test]
fn decode_next() {

@ -4,7 +4,7 @@
*/
//! Offers information about how an instructions accesses the FPU status registers.
extern crate bddisasm_sys as ffi;
use super::decode_error::DecodeError;
/// The mode in which a FPU status flag is accessed.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
@ -19,15 +19,16 @@ pub enum FpuFlagsAccess {
Undefined,
}
impl From<u8> for FpuFlagsAccess {
fn from(value: u8) -> FpuFlagsAccess {
let value = value as u32;
#[doc(hidden)]
impl FpuFlagsAccess {
pub(crate) fn from_raw(value: u8) -> Result<Self, DecodeError> {
let value = u32::from(value);
match value {
ffi::ND_FPU_FLAG_SET_0 => FpuFlagsAccess::Cleared,
ffi::ND_FPU_FLAG_SET_1 => FpuFlagsAccess::Set,
ffi::ND_FPU_FLAG_MODIFIED => FpuFlagsAccess::Modified,
ffi::ND_FPU_FLAG_UNDEFINED => FpuFlagsAccess::Undefined,
_ => panic!("Unexpected FPU flag access: {}", value),
ffi::ND_FPU_FLAG_SET_0 => Ok(FpuFlagsAccess::Cleared),
ffi::ND_FPU_FLAG_SET_1 => Ok(FpuFlagsAccess::Set),
ffi::ND_FPU_FLAG_MODIFIED => Ok(FpuFlagsAccess::Modified),
ffi::ND_FPU_FLAG_UNDEFINED => Ok(FpuFlagsAccess::Undefined),
_ => Err(DecodeError::InternalError(value.into())),
}
}
}
@ -46,13 +47,13 @@ pub struct FpuFlags {
}
#[doc(hidden)]
impl From<ffi::ND_FPU_FLAGS> for FpuFlags {
fn from(flags: ffi::ND_FPU_FLAGS) -> FpuFlags {
FpuFlags {
c0: FpuFlagsAccess::from(flags.C0()),
c1: FpuFlagsAccess::from(flags.C1()),
c2: FpuFlagsAccess::from(flags.C2()),
c3: FpuFlagsAccess::from(flags.C3()),
}
impl FpuFlags {
pub(crate) fn from_raw(flags: ffi::ND_FPU_FLAGS) -> Result<Self, DecodeError> {
Ok(Self {
c0: FpuFlagsAccess::from_raw(flags.C0())?,
c1: FpuFlagsAccess::from_raw(flags.C1())?,
c2: FpuFlagsAccess::from_raw(flags.C2())?,
c3: FpuFlagsAccess::from_raw(flags.C3())?,
})
}
}

@ -4,10 +4,8 @@
*/
//! Instruction categories.
extern crate bddisasm_sys as ffi;
use super::decode_error;
use std::convert::TryFrom;
use super::decode_error::DecodeError;
use core::convert::TryFrom;
/// Instruction category.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
@ -120,13 +118,11 @@ pub enum Category {
#[doc(hidden)]
impl TryFrom<ffi::ND_INS_CATEGORY> for Category {
type Error = decode_error::DecodeError;
type Error = DecodeError;
fn try_from(value: ffi::ND_INS_CATEGORY) -> Result<Self, Self::Error> {
match value {
ffi::_ND_INS_TYPE::ND_CAT_INVALID => {
Err(decode_error::DecodeError::UnknownInstruction(value as u32))
}
ffi::_ND_INS_TYPE::ND_CAT_INVALID => Err(DecodeError::InternalError(value as u64)),
ffi::_ND_INS_TYPE::ND_CAT_3DNOW => Ok(Category::I3dnow),
ffi::_ND_INS_TYPE::ND_CAT_AES => Ok(Category::Aes),
ffi::_ND_INS_TYPE::ND_CAT_AESKL => Ok(Category::Aeskl),

@ -4,10 +4,8 @@
*/
//! Instruction sets.
extern crate bddisasm_sys as ffi;
use super::decode_error;
use std::convert::TryFrom;
use super::decode_error::DecodeError;
use core::convert::TryFrom;
/// ISA set.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
@ -133,13 +131,11 @@ pub enum IsaSet {
#[doc(hidden)]
impl TryFrom<ffi::ND_INS_SET> for IsaSet {
type Error = decode_error::DecodeError;
type Error = DecodeError;
fn try_from(value: ffi::ND_INS_SET) -> Result<Self, Self::Error> {
match value {
ffi::_ND_INS_SET::ND_SET_INVALID => {
Err(decode_error::DecodeError::UnknownInstruction(value as u32))
}
ffi::_ND_INS_SET::ND_SET_INVALID => Err(DecodeError::InternalError(value as u64)),
ffi::_ND_INS_SET::ND_SET_3DNOW => Ok(IsaSet::I3dnow),
ffi::_ND_INS_SET::ND_SET_ADX => Ok(IsaSet::Adx),
ffi::_ND_INS_SET::ND_SET_AES => Ok(IsaSet::Aes),

@ -4,12 +4,14 @@
*/
//! bddisasm x86/x64 instruction decoder
//!
//! Rust bindings for the [bddisasm](https://github.com/bitdefender/bddisasm) x86/x64 decoder library, built on top
//! of [bddisasm-sys](https://crates.io/crates/bddisasm-sys).
//! `no_std` Rust bindings for the [bddisasm](https://github.com/bitdefender/bddisasm) x86/x64 decoder library, built
//! on top of [bddisasm-sys](https://crates.io/crates/bddisasm-sys).
//!
//! It supports all existing x86 instruction, offering a wide range of information about each one, including:
//! It supports all existing 16-bit, 32-bit and 64-bit instruction, offering a wide range of information about each one,
//! including:
//!
//! - operands (implicit and explicit)
//! - implicit operands
//! - explicit operands
//! - access mode for each operand
//! - CPUID feature flags
//! - CPU modes in which an instruction is valid
@ -27,11 +29,11 @@
//!
//! ## Decoding one instruction
//!
//! Use [DecodedInstruction::decode](crate::decoded_instruction::DecodedInstruction::decode) to decode an instruction
//! Use [`DecodedInstruction::decode`](crate::decoded_instruction::DecodedInstruction::decode) to decode an instruction
//! from a chunk of code.
//!
//! ```
//! use bddisasm::decoded_instruction::{DecodedInstruction, DecodeMode, Mnemonic};
//! use bddisasm::{DecodedInstruction, DecodeMode, Mnemonic};
//!
//! let code = vec![0x31, 0xc0];
//! match DecodedInstruction::decode(&code, DecodeMode::Bits32) {
@ -45,10 +47,10 @@
//!
//! ## Decoding multiple instructions
//!
//! Use [Decoder](crate::decoder::Decoder) to decode multiple instructions from a chunk of code.
//! Use [`Decoder`](crate::decoder::Decoder) to decode multiple instructions from a chunk of code.
//!
//! ```
//! use bddisasm::decoder::{Decoder, DecodeMode};
//! use bddisasm::{Decoder, DecodeMode};
//!
//! let code = [
//! // ENCLS
@ -79,11 +81,11 @@
//! WRMSR
//! ```
//!
//! Use [Decoder::decode_next_with_info](crate::decoder::Decoder::decode_next_with_info) to get information about the
//! Use [`Decoder::decode_next_with_info`](crate::decoder::Decoder::decode_next_with_info) to get information about the
//! offset inside the code chunk at which an instruction was decoded from.
//!
//! ```
//! use bddisasm::decoder::{Decoder, DecodeMode};
//! use bddisasm::{Decoder, DecodeMode};
//!
//! let code = [
//! // ENCLS
@ -122,10 +124,9 @@
//! each type of operand. Bellow is a minimal example that looks at a memory operand.
//!
//! ```
//! # use bddisasm::decode_error::DecodeError;
//! # use bddisasm::DecodeError;
//! # fn test() -> Result<(), DecodeError> {
//! use bddisasm::decoded_instruction::{DecodedInstruction, DecodeMode};
//! use bddisasm::operand::OpInfo;
//! use bddisasm::{DecodedInstruction, DecodeMode, OpInfo};
//!
//! // ` MOV rax, qword ptr [rcx+r15*2]`
//! let code = b"\x4a\x8b\x04\x79";
@ -177,6 +178,21 @@
//! Scale: 2
//! No displacement
//! ```
//!
//! ## Accessing the raw bindings
//!
//! The raw `bddisasm_sys` bindings are available via the `ffi` re-export.
//!
//! # Feature Flags
//!
//! - `std` - adds a `std` dependency - the only visible difference when doing this is that [`DecodeError`] implements
//! the `Error` trait
//!
#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
pub extern crate bddisasm_sys as ffi;
pub mod cpu_modes;
pub mod cpuid;
pub mod decode_error;
@ -189,3 +205,13 @@ pub mod mnemonic;
pub mod operand;
pub mod rflags;
pub mod tuple;
pub use crate::decode_error::DecodeError;
pub use crate::decoded_instruction::{DecodeMode, DecodeResult, DecodedInstruction, OperandSize};
pub use crate::decoder::Decoder;
pub use crate::instruction_category::Category;
pub use crate::isa_set::IsaSet;
pub use crate::mnemonic::Mnemonic;
pub use crate::operand::{
OpAddr, OpInfo, OpMem, OpReg, OpRegType, OpSize, Operand, OperandsLookup,
};

@ -4,10 +4,8 @@
*/
//! Mnemonics.
extern crate bddisasm_sys as ffi;
use super::decode_error;
use std::convert::TryFrom;
use super::decode_error::DecodeError;
use core::convert::TryFrom;
/// Uniquely identifies an instruction.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
@ -1601,13 +1599,11 @@ pub enum Mnemonic {
#[doc(hidden)]
impl TryFrom<ffi::ND_INS_CLASS> for Mnemonic {
type Error = decode_error::DecodeError;
type Error = DecodeError;
fn try_from(value: ffi::ND_INS_CLASS) -> Result<Self, Self::Error> {
match value {
ffi::_ND_INS_CLASS::ND_INS_INVALID => {
Err(decode_error::DecodeError::UnknownInstruction(value as u32))
}
ffi::_ND_INS_CLASS::ND_INS_INVALID => Err(DecodeError::InternalError(value as u64)),
ffi::_ND_INS_CLASS::ND_INS_AAA => Ok(Mnemonic::Aaa),
ffi::_ND_INS_CLASS::ND_INS_AAD => Ok(Mnemonic::Aad),
ffi::_ND_INS_CLASS::ND_INS_AAM => Ok(Mnemonic::Aam),

File diff suppressed because it is too large Load Diff

@ -4,8 +4,6 @@
*/
//! Describes the bits in the FLAGS register.
extern crate bddisasm_sys as ffi;
/// Carry flag.
pub const CF: u32 = ffi::NDR_RFLAG_CF;
/// Parity flag.

@ -4,7 +4,7 @@
*/
//! Instruction tuple type.
extern crate bddisasm_sys as ffi;
use super::decode_error::DecodeError;
/// Instruction tuple type.
///
@ -50,73 +50,76 @@ pub enum Tuple {
}
#[doc(hidden)]
impl From<ffi::ND_TUPLE> for Tuple {
fn from(value: ffi::ND_TUPLE) -> Tuple {
match value {
ffi::_ND_TUPLE::ND_TUPLE_None => Tuple::None,
ffi::_ND_TUPLE::ND_TUPLE_FV => Tuple::Fv,
ffi::_ND_TUPLE::ND_TUPLE_HV => Tuple::Hv,
ffi::_ND_TUPLE::ND_TUPLE_QV => Tuple::Qv,
ffi::_ND_TUPLE::ND_TUPLE_T1S8 => Tuple::T1S8,
ffi::_ND_TUPLE::ND_TUPLE_T1S16 => Tuple::T1S16,
ffi::_ND_TUPLE::ND_TUPLE_T1S => Tuple::T1S,
ffi::_ND_TUPLE::ND_TUPLE_T1F => Tuple::T1F,
ffi::_ND_TUPLE::ND_TUPLE_T2 => Tuple::T2,
ffi::_ND_TUPLE::ND_TUPLE_T4 => Tuple::T4,
ffi::_ND_TUPLE::ND_TUPLE_T8 => Tuple::T8,
ffi::_ND_TUPLE::ND_TUPLE_FVM => Tuple::Fvm,
ffi::_ND_TUPLE::ND_TUPLE_HVM => Tuple::Hvm,
ffi::_ND_TUPLE::ND_TUPLE_QVM => Tuple::Qvm,
ffi::_ND_TUPLE::ND_TUPLE_OVM => Tuple::OVm,
ffi::_ND_TUPLE::ND_TUPLE_M128 => Tuple::M128,
ffi::_ND_TUPLE::ND_TUPLE_DUP => Tuple::Dup,
ffi::_ND_TUPLE::ND_TUPLE_T1_4X => Tuple::T14X,
// NOTE: when updating this take care to also update the `From<u32>` implementation!
// TODO: any way of keeping these in sync automagically?
}
}
}
impl From<u32> for Tuple {
fn from(value: u32) -> Tuple {
impl Tuple {
pub(crate) fn from_raw(value: u32) -> Result<Self, DecodeError> {
if value == ffi::_ND_TUPLE::ND_TUPLE_None as u32 {
Tuple::None
Ok(Tuple::None)
} else if value == ffi::_ND_TUPLE::ND_TUPLE_FV as u32 {
Tuple::Fv
Ok(Tuple::Fv)
} else if value == ffi::_ND_TUPLE::ND_TUPLE_HV as u32 {
Tuple::Hv
Ok(Tuple::Hv)
} else if value == ffi::_ND_TUPLE::ND_TUPLE_QV as u32 {
Tuple::Qv
Ok(Tuple::Qv)
} else if value == ffi::_ND_TUPLE::ND_TUPLE_T1S8 as u32 {
Tuple::T1S8
Ok(Tuple::T1S8)
} else if value == ffi::_ND_TUPLE::ND_TUPLE_T1S16 as u32 {
Tuple::T1S16
Ok(Tuple::T1S16)
} else if value == ffi::_ND_TUPLE::ND_TUPLE_T1S as u32 {
Tuple::T1S
Ok(Tuple::T1S)
} else if value == ffi::_ND_TUPLE::ND_TUPLE_T1F as u32 {
Tuple::T1F
Ok(Tuple::T1F)
} else if value == ffi::_ND_TUPLE::ND_TUPLE_T2 as u32 {
Tuple::T2
Ok(Tuple::T2)
} else if value == ffi::_ND_TUPLE::ND_TUPLE_T4 as u32 {
Tuple::T4
Ok(Tuple::T4)
} else if value == ffi::_ND_TUPLE::ND_TUPLE_T8 as u32 {
Tuple::T8
Ok(Tuple::T8)
} else if value == ffi::_ND_TUPLE::ND_TUPLE_FVM as u32 {
Tuple::Fvm
Ok(Tuple::Fvm)
} else if value == ffi::_ND_TUPLE::ND_TUPLE_HVM as u32 {
Tuple::Hvm
Ok(Tuple::Hvm)
} else if value == ffi::_ND_TUPLE::ND_TUPLE_QVM as u32 {
Tuple::Qvm
Ok(Tuple::Qvm)
} else if value == ffi::_ND_TUPLE::ND_TUPLE_OVM as u32 {
Tuple::OVm
Ok(Tuple::OVm)
} else if value == ffi::_ND_TUPLE::ND_TUPLE_M128 as u32 {
Tuple::M128
Ok(Tuple::M128)
} else if value == ffi::_ND_TUPLE::ND_TUPLE_DUP as u32 {
Tuple::Dup
Ok(Tuple::Dup)
} else if value == ffi::_ND_TUPLE::ND_TUPLE_T1_4X as u32 {
Tuple::T14X
Ok(Tuple::T14X)
} else {
panic!("Unknown tuple: {}", value)
Err(DecodeError::InternalError(value.into()))
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn check_all_tuples() {
// This is a really contrieved way of making sure that we check all variants of `ffi::_ND_TUPLE`. If a new
// one is added, this will fail to build. We do this because `Tuple::from_raw` takes an `u32`.
// NOTE: When a new variant is added, `Tuple::from_raw` must be updated.
match ffi::_ND_TUPLE::ND_TUPLE_None {
ffi::_ND_TUPLE::ND_TUPLE_None => {}
ffi::_ND_TUPLE::ND_TUPLE_FV => {}
ffi::_ND_TUPLE::ND_TUPLE_HV => {}
ffi::_ND_TUPLE::ND_TUPLE_QV => {}
ffi::_ND_TUPLE::ND_TUPLE_T1S8 => {}
ffi::_ND_TUPLE::ND_TUPLE_T1S16 => {}
ffi::_ND_TUPLE::ND_TUPLE_T1S => {}
ffi::_ND_TUPLE::ND_TUPLE_T1F => {}
ffi::_ND_TUPLE::ND_TUPLE_T2 => {}
ffi::_ND_TUPLE::ND_TUPLE_T4 => {}
ffi::_ND_TUPLE::ND_TUPLE_T8 => {}
ffi::_ND_TUPLE::ND_TUPLE_FVM => {}
ffi::_ND_TUPLE::ND_TUPLE_HVM => {}
ffi::_ND_TUPLE::ND_TUPLE_QVM => {}
ffi::_ND_TUPLE::ND_TUPLE_OVM => {}
ffi::_ND_TUPLE::ND_TUPLE_M128 => {}
ffi::_ND_TUPLE::ND_TUPLE_DUP => {}
ffi::_ND_TUPLE::ND_TUPLE_T1_4X => {}
}
}
}

@ -0,0 +1,12 @@
#!/bin/bash
set -e
cd bddisasm-sys
rm -rf LICENSE
ln -s ../../../LICENSE .
cd csrc
rm -rf bddisasm
ln -s ../../../../bddisasm/ .
rm -rf inc
ln -s ../../../../inc/ .

@ -1,6 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
@ -9,6 +13,10 @@
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
@ -43,11 +51,22 @@
<CharacterSet>Unicode</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
@ -60,9 +79,15 @@
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>14.0.23107.0</_ProjectFileVersion>
@ -77,6 +102,11 @@
<IntDir>$(SolutionDir)_intdir\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<OutDir>$(SolutionDir)bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)_intdir\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)_intdir\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
@ -89,6 +119,13 @@
<LinkIncremental>false</LinkIncremental>
<LibraryPath>$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<OutDir>$(SolutionDir)bin\$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)_intdir\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
<IgnoreImportLibrary>false</IgnoreImportLibrary>
<LinkIncremental>false</LinkIncremental>
<LibraryPath>$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
@ -141,6 +178,33 @@
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
</ProjectReference>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<Midl />
<ClCompile>
<AdditionalOptions>/D "AMD64" %(AdditionalOptions)</AdditionalOptions>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\inc;..\bdshemu;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<ProgramDataBaseFileName>$(SolutionDir)bin\$(Platform)\$(Configuration)\$(ProjectName).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>bddisasm.lib;bdshemu.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)disasmtool.exe</OutputFile>
<AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)\$(Configuration)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<IgnoreSpecificDefaultLibraries>LIBCMTD;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
</Link>
<ProjectReference>
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
</ProjectReference>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>MaxSpeed</Optimization>
@ -200,6 +264,38 @@
<TargetMachine>MachineX64</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<Midl />
<ClCompile>
<AdditionalOptions>/D "AMD64" %(AdditionalOptions)</AdditionalOptions>
<Optimization>MaxSpeed</Optimization>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<AdditionalIncludeDirectories>..\inc;..\bdshemu;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<FunctionLevelLinking>false</FunctionLevelLinking>
<WarningLevel>Level4</WarningLevel>
<TreatWarningAsError>true</TreatWarningAsError>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<ProgramDataBaseFileName>$(SolutionDir)bin\$(Platform)\$(Configuration)\$(ProjectName).pdb</ProgramDataBaseFileName>
</ClCompile>
<ProjectReference>
<UseLibraryDependencyInputs>true</UseLibraryDependencyInputs>
</ProjectReference>
<Link>
<AdditionalDependencies>bddisasm.lib;bdshemu.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)disasmtool.exe</OutputFile>
<AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)\$(Configuration)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<IgnoreSpecificDefaultLibraries>LIBCMT;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="disasmtool.c" />
</ItemGroup>

@ -12,7 +12,7 @@ if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release")
endif ()
add_executable(disasmtool disasmtool.cpp dumpers.cpp)
add_executable(disasmtool disasmtool.cpp dumpers.cpp rapidjson.cpp)
target_compile_options(
disasmtool
@ -43,15 +43,11 @@ if (NOT TARGET bddisasm)
find_package(bddisasm REQUIRED)
endif ()
find_package(RapidJSON QUIET)
find_package(RapidJSON QUIET REQUIRED)
target_link_libraries(disasmtool PRIVATE bddisasm::bddisasm bddisasm::bdshemu)
if (RapidJSON_FOUND)
# :( https://github.com/satishbabariya/modern-cmake#good-boys-export-their-targets
target_include_directories(disasmtool PRIVATE ${RapidJSON_INCLUDE_DIRS})
target_sources(disasmtool PRIVATE rapidjson.cpp)
target_compile_definitions(disasmtool PRIVATE HAS_RAPIDJSON)
endif ()
# :( https://github.com/satishbabariya/modern-cmake#good-boys-export-their-targets
target_include_directories(disasmtool PRIVATE ${RapidJSON_INCLUDE_DIRS})
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Release")
include(CheckIPOSupported)

@ -7,13 +7,8 @@
#include <ctime>
#include <cstdint>
#ifdef HAS_RAPIDJSON
#include <rapidjson/stringbuffer.h>
using StringBuffer = rapidjson::StringBuffer;
#else
#include "external/json.hpp"
using json = nlohmann::json;
#endif
extern "C"

@ -496,14 +496,14 @@ void shemu_log(PCHAR msg)
printf("%s", msg);
}
bool shemu_access_mem(void * /* Ctx */, uint64_t /* Gla */, size_t Size, uint8_t *Buffer, bool Store)
ND_BOOL shemu_access_mem(void * /* Ctx */, uint64_t /* Gla */, size_t Size, uint8_t *Buffer, ND_BOOL Store)
{
if (!Store)
{
memset(Buffer, 0, Size);
}
return true;
return ND_TRUE;
}
void shemu(options &opts)

Loading…
Cancel
Save