Skip to content

Complete bindings with Bindgen #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 21, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 0 additions & 4 deletions .gitmodules

This file was deleted.

8 changes: 8 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
language: rust
rust:
- stable
- beta
- nightly
matrix:
allow_failures:
- rust: nightly
9 changes: 7 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,16 @@ repository = "https://github.com/m4b/capstone-sys"
libc = "0.2"

[build-dependencies]
bindgen = "0.26.3"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be optional with undeleted bindings; just need to add a feature flag on the bindings and reexport iiuc

pkg-config = "0.3"
gcc = "0.3"
cmake = {optional = true, version = "0.1.2"}
lazy_static = "0.2"

[features]
# use bundled capstone by default
default = []
build_src = []
build_src_cmake = ["cmake", "build_src"]

use_system_capstone = []
build_capstone_cmake = ["cmake"]
use_bundled_capstone_bindings = []
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,14 @@
# capstone-sys
libcapstone3 system bindings for Rust

Low-level, unsafe Rust bindings for the `capstone` disassembly library.


## Features

`capstone-sys` will build differently based on [features](http://doc.crates.io/manifest.html#the-features-section) that are specified in `Cargo.toml`.

`capstone-sys` supports the following features:

* `use_system_capstone`: use the system capstone instead of the bundled copy of the `capstone` library.
* `build_capstone_cmake`: if using the bundled `capstone` library, then build `capstone` using `cmake`.
* `use_bundled_capstone_bindings`: instead of using [`bindgen`](https://github.com/rust-lang-nursery/rust-bindgen), use the pre-generated capstone bindings (if available for the current platform).
190 changes: 177 additions & 13 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,40 +1,204 @@
//! The following environment variables affect the build:
//!
//! * `UPDATE_CAPSTONE_BINDINGS`: setting indicates that the pre-generated `capstone.rs` should be
//! updated with the output bindgen
//! * `CAPSTONE_BUILD_DEBUG`: write debug output to file

extern crate bindgen;
extern crate gcc;
extern crate pkg_config;
#[cfg(feature="build_src_cmake")]

#[cfg(feature = "build_src_cmake")]
extern crate cmake;

use std::path::{Path};
#[macro_use]
extern crate lazy_static;

use std::fs::{File, copy};
use std::path::PathBuf;
use std::process::Command;
use std::env;
use std::io::Write;
use std::sync::Mutex;

include!("common.rs");

/// Indicates how capstone library should be linked
enum LinkType {
Dynamic,
Static,
}

static DEBUG_FILE_ENV_VAR: &'static str = "CAPSTONE_BUILD_DEBUG";

// Open/truncate debug file once at the beginning of execution
lazy_static! {
static ref BUILD_DEBUG_LOG_FILE: Mutex<Option<File>> = Mutex::new(
match env::var(DEBUG_FILE_ENV_VAR) {
Err(_) => None,
Ok(filename) => {
let file = File::create(&filename)
.expect(&format!("Could not open debug log \"{}\"", filename));
Some(file)
}
}
);
}

/// Log to debug file
macro_rules! debug_println(
($($arg:tt)*) => { {
if let Some(ref mut file) = *BUILD_DEBUG_LOG_FILE.lock().unwrap() {
writeln!(file, $($arg)*)
.expect("failed printing to stderr");
}
} }
);

#[cfg(feature = "build_src_cmake")]
fn cmake() {
debug_println!("Building capstone with cmake");
let mut cfg = cmake::Config::new("capstone");
let dst = cfg.build();
println!("cargo:rustc-link-search=native={}/lib", dst.display());
}

/// Search for header in search paths
fn find_capstone_header(header_search_paths: &Vec<PathBuf>, name: &str) -> Option<PathBuf> {
for search_path in header_search_paths.iter() {
let potential_file = search_path.join(name);
if potential_file.is_file() {
return Some(potential_file);
}
}
None
}

/// Create bindings using bindgen
fn write_bindgen_bindings(header_search_paths: &Vec<PathBuf>, update_pregenerated_bindings: bool) {
debug_println!(
"Writing bindgen bindings with search paths {:?}",
header_search_paths
);


let mut builder = bindgen::Builder::default()
.unstable_rust(false)
.header(
find_capstone_header(header_search_paths, "capstone.h")
.expect("Could not find header")
.to_str()
.unwrap(),
)
.disable_name_namespacing()
.prepend_enum_name(false)
.generate_comments(true)
.constified_enum_module("[^_]+_reg$"); // Some registers have aliases


// Whitelist cs_.* functions and types
let pattern = String::from("cs_.*");
builder = builder
.whitelisted_function(pattern.clone())
.whitelisted_type(pattern.clone());

// Whitelist types with architectures
for arch in ARCH_INCLUDES {
let pattern = format!(".*(^|_){}(_|$).*", arch.cs_name);
builder = builder.whitelisted_type(pattern);
}

let bindings = builder.generate().expect("Unable to generate bindings");

// Write bindings to $OUT_DIR/bindings.rs
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join(BINDINGS_FILE);
bindings.write_to_file(out_path.clone()).expect(
"Unable to write bindings",
);

if update_pregenerated_bindings {
debug_println!("Updating pre-generated capstone bindings");
let stored_bindgen_header: PathBuf =
[
env::var("CARGO_MANIFEST_DIR").expect("Could not find cargo environment variable"),
"pre_generated".into(),
BINDINGS_FILE.into(),
].iter()
.collect();
debug_println!(
"Updating capstone bindings at \"{}\"",
stored_bindgen_header.to_str().unwrap()
);
copy(out_path, stored_bindgen_header).expect("Unable to update capstone bindings");
}
}

fn main() {
if !cfg!(feature = "build_src") && pkg_config::find_library("capstone").is_ok() {
let link_type: Option<LinkType>;

// C header search paths
let mut header_search_paths: Vec<PathBuf> = Vec::new();

if cfg!(feature = "use_system_capstone") {
debug_println!("Using system capstone library");

assert!(
!cfg!(feature = "build_capstone_cmake"),
"build_capstone_cmake feature is only valid when using bundled cmake"
);

let capstone_lib =
pkg_config::find_library("capstone").expect("Could not find system capstone");
header_search_paths.append(&mut capstone_lib.include_paths.clone());
link_type = Some(LinkType::Dynamic);
} else {
if !Path::new("capstone/.git").exists() {
let _ = Command::new("git").args(&["submodule", "update", "--init", "--depth", "5"])
.status();
}
if cfg!(feature = "build_src_cmake") {
debug_println!("Using bundled capstone library");

if cfg!(feature = "build_capstone_cmake") {
#[cfg(feature = "build_src_cmake")]
cmake();
} else {
//let target = env::var("TARGET").unwrap();
//let windows = target.contains("windows");
// TODO: need to add this argument for windows 64-bit, msvc, dunno, read the COMPILE_MSVC.txt
// file cygwin-mingw64
// TODO: need to add this argument for windows 64-bit, msvc, dunno, read
// COMPILE_MSVC.txt file cygwin-mingw64
let out_dir = env::var("OUT_DIR").unwrap();
let _ = Command::new("./make.sh").current_dir("capstone").status();
let _ = Command::new("./make.sh")
.current_dir("capstone")
.status();
let capstone = "libcapstone.a";
let _ = Command::new("cp").current_dir("capstone").arg(&capstone).arg(&out_dir).status();
let _ = Command::new("cp")
.current_dir("capstone")
.arg(&capstone)
.arg(&out_dir)
.status();
println!("cargo:rustc-link-search=native={}", out_dir);
}
header_search_paths.push(PathBuf::from("capstone/include"));
link_type = Some(LinkType::Static);
}
println!("cargo:rustc-link-lib=static=capstone");

match link_type.expect("Must specify link type") {
LinkType::Dynamic => {
println!("cargo:rustc-link-lib=dylib=capstone");
}
LinkType::Static => {
println!("cargo:rustc-link-lib=static=capstone");
}
}

// If UPDATE_CAPSTONE_BINDINGS is set, then updated the pre-generated capstone bindings
let update_pregenerated_bindings = env::var("UPDATE_CAPSTONE_BINDINGS").is_ok();
if update_pregenerated_bindings {
assert!(
!cfg!(feature = "use_bundled_capstone_bindings"),
concat!(
"Setting UPDATE_CAPSTONE_BINDINGS only makes ",
"sense when NOT enabling feature use_bundled_capstone_bindings"
)
);
}

debug_println!("Creating capstone bindings with bindgen");
write_bindgen_bindings(&header_search_paths, update_pregenerated_bindings);
}
1 change: 0 additions & 1 deletion capstone
Submodule capstone deleted from 8308ac
14 changes: 14 additions & 0 deletions capstone/.appveyor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
version: 3.0.4-{build}

os:
- Visual Studio 2015

before_build:
- call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64

build_script:
- mkdir build
- cd build
- cmake -DCMAKE_BUILD_TYPE=RELEASE -G "NMake Makefiles" ..
- nmake

112 changes: 112 additions & 0 deletions capstone/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Object files
*.o
*.ko

# Gcc dependency-tracking files
*.d

# Libraries
*.lib
*.a

# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib

# Executables
*.exe
*.out
*.app

# python
bindings/python/build/
bindings/python/capstone.egg-info/
*.pyc

# java
bindings/java/capstone.jar

# ocaml
bindings/ocaml/*.cmi
bindings/ocaml/*.cmx
bindings/ocaml/*.cmxa
bindings/ocaml/*.mli
bindings/ocaml/test
bindings/ocaml/test_arm
bindings/ocaml/test_arm64
bindings/ocaml/test_mips
bindings/ocaml/test_x86
bindings/ocaml/test_detail
bindings/ocaml/test_ppc
bindings/ocaml/test_sparc
bindings/ocaml/test_systemz
bindings/ocaml/test_xcore


# test binaries
tests/test
tests/test_detail
tests/test_iter
tests/test_arm
tests/test_arm64
tests/test_mips
tests/test_x86
tests/test_ppc
tests/test_skipdata
tests/test_sparc
tests/test_systemz
tests/test_xcore
tests/*.static
tests/test_basic
tests/test_customized_mnem


# regress binaries
suite/regress/invalid_read_in_print_operand


# vim tmp file
*.swp
*~

capstone.pc

# local files
_*

# freebsd ports: generated file with "make makesum" command
packages/freebsd/ports/devel/capstone/distinfo

# VisualStudio
ProjectUpgradeLog.log
Debug/
Release/
ipch/
*.sdf
*.opensdf
*.suo
*.user
*.backup
*.VC.db
*.VC.opendb

# CMake build directories
build*/

# Xcode
xcode/Capstone.xcodeproj/xcuserdata
xcode/Capstone.xcodeproj/project.xcworkspace/xcuserdata

# suite/
test_arm_regression
test_arm_regression.o
fuzz_harness
test_iter_benchmark


*.s
.DS_Store

cstool/cstool
Loading