bddisasm_sys/
lib.rs

1/*
2 * Copyright (c) 2021 Bitdefender
3 * SPDX-License-Identifier: Apache-2.0
4 */
5//! Rust bindings for [bddisasm](https://github.com/bitdefender/bddisasm).
6//!
7//! See [bddisasm](https://crates.io/crates/bddisasm) if you're looking for a Rust wrapper for these bindings.
8//!
9//! # Requirements
10//!
11//! [bindgen](https://crates.io/crates/bindgen) is used to generate the bindings at build time. Because of this, users
12//! need to have `clang` installed.
13//! Check the [bindgen documentation](https://rust-lang.github.io/rust-bindgen/requirements.html) for more information.
14#![cfg_attr(not(test), no_std)]
15#![allow(non_camel_case_types)]
16#![allow(non_snake_case)]
17#![allow(non_upper_case_globals)]
18#![allow(deref_nullptr)] // See https://github.com/rust-lang/rust-bindgen/issues/1651
19#![allow(clippy::all)]
20include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
21
22#[cfg(test)]
23mod tests {
24    use super::*;
25    use ::std::os::raw::c_char;
26    use std::mem;
27
28    #[test]
29    fn get_version() {
30        let mut major: u32 = 0;
31        let mut minor: u32 = 0;
32        let mut revision: u32 = 0;
33        let mut build_date: *const c_char = std::ptr::null();
34        let mut build_time: *const c_char = std::ptr::null();
35
36        unsafe {
37            NdGetVersion(
38                &mut major,
39                &mut minor,
40                &mut revision,
41                &mut build_date,
42                &mut build_time,
43            );
44        }
45
46        println!("major: {} minor: {} rev: {}", major, minor, revision);
47
48        let build_date = unsafe { std::ffi::CStr::from_ptr(build_date) };
49        let build_date = build_date.to_str().unwrap().to_string();
50        let build_time = unsafe { std::ffi::CStr::from_ptr(build_time) };
51        let build_time = build_time.to_str().unwrap().to_string();
52        println!("Build date: {} build time: {}", build_date, build_time);
53
54        // There are no other asserts in this test. Enforcing a known minor version is not worth it, we mainly want to
55        // see that `NdGetVersion` works.
56        assert_eq!(major, 2);
57    }
58
59    fn do_decode(code: &[u8]) -> (INSTRUX, NDSTATUS) {
60        let mut instrux: mem::MaybeUninit<INSTRUX> = mem::MaybeUninit::uninit();
61        let instrux = instrux.as_mut_ptr();
62
63        let status = unsafe {
64            NdDecodeEx(
65                instrux,
66                code.as_ptr(),
67                code.len() as u64,
68                ND_CODE_32 as u8,
69                ND_DATA_32 as u8,
70            )
71        };
72
73        (unsafe { *instrux }, status)
74    }
75
76    #[test]
77    fn decode() {
78        let code = vec![0x90];
79        let (instrux, status) = do_decode(&code);
80
81        assert_eq!(status, 0, "Failed to decode instruction {:#x?}", code);
82        assert_eq!(instrux.Instruction, _ND_INS_CLASS::ND_INS_NOP);
83    }
84
85    #[test]
86    fn format() {
87        let code = vec![0x89, 0x29];
88        let (instrux, status) = do_decode(&code);
89
90        assert_eq!(status, 0, "Failed to decode instruction {:#x?}", code);
91
92        let mut buffer: [i8; ND_MIN_BUF_SIZE as usize] = [0; ND_MIN_BUF_SIZE as usize];
93        let status = unsafe { NdToText(&instrux, 0, ND_MIN_BUF_SIZE, buffer.as_mut_ptr()) };
94        assert_eq!(status, 0, "Failed to decode format {:#x?}", code);
95
96        let text = String::from_utf8(buffer.iter().map(|&c| c as u8).collect()).unwrap();
97        let text = text.trim_matches(char::from(0));
98        assert_eq!(text, "MOV       dword ptr [ecx], ebp");
99    }
100}