Skip to content

Commit

Permalink
Initial commit for NIF inspection tool
Browse files Browse the repository at this point in the history
  • Loading branch information
filmor committed May 29, 2024
1 parent 3d7eb93 commit 2366e44
Show file tree
Hide file tree
Showing 6 changed files with 269 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ members = [
"rustler_tests/native/rustler_serde_test",
"rustler_tests/native/dynamic_load",
"rustler_tests/native/rustler_compile_tests",
"rustler_benchmarks/native/benchmark",
"rustler_benchmarks/native/benchmark", "rustler_tool",
]
default-members = [
"rustler",
Expand Down
2 changes: 2 additions & 0 deletions rustler_tool/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[target.x86_64-unknown-linux-gnu]
rustflags = [ "-C", "link-args=-Wl,-export-dynamic" ]
9 changes: 9 additions & 0 deletions rustler_tool/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "rustler_tool"
version = "0.1.0"
edition = "2021"

[dependencies]
clap = { version = "4.5", features = [ "derive" ] }
libloading = "0.8"
rustler_sys = { version = "2.4.0", path = "../rustler_sys" }
148 changes: 148 additions & 0 deletions rustler_tool/src/fake_symbols.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
#[no_mangle]
pub static enif_alloc: usize = 0;
#[no_mangle]
pub static enif_alloc_binary: usize = 0;
#[no_mangle]
pub static enif_alloc_env: usize = 0;
#[no_mangle]
pub static enif_binary_to_term: usize = 0;
#[no_mangle]
pub static enif_clear_env: usize = 0;
#[no_mangle]
pub static enif_compare: usize = 0;
#[no_mangle]
pub static enif_consume_timeslice: usize = 0;
#[no_mangle]
pub static enif_free: usize = 0;
#[no_mangle]
pub static enif_free_env: usize = 0;
#[no_mangle]
pub static enif_get_atom: usize = 0;
#[no_mangle]
pub static enif_get_atom_length: usize = 0;
#[no_mangle]
pub static enif_get_double: usize = 0;
#[no_mangle]
pub static enif_get_int: usize = 0;
#[no_mangle]
pub static enif_get_list_cell: usize = 0;
#[no_mangle]
pub static enif_get_list_length: usize = 0;
#[no_mangle]
pub static enif_get_local_pid: usize = 0;
#[no_mangle]
pub static enif_get_long: usize = 0;
#[no_mangle]
pub static enif_get_map_size: usize = 0;
#[no_mangle]
pub static enif_get_map_value: usize = 0;
#[no_mangle]
pub static enif_get_resource: usize = 0;
#[no_mangle]
pub static enif_get_tuple: usize = 0;
#[no_mangle]
pub static enif_get_uint: usize = 0;
#[no_mangle]
pub static enif_get_ulong: usize = 0;
#[no_mangle]
pub static enif_hash: usize = 0;
#[no_mangle]
pub static enif_inspect_binary: usize = 0;
#[no_mangle]
pub static enif_inspect_iolist_as_binary: usize = 0;
#[no_mangle]
pub static enif_is_atom: usize = 0;
#[no_mangle]
pub static enif_is_binary: usize = 0;
#[no_mangle]
pub static enif_is_empty_list: usize = 0;
#[no_mangle]
pub static enif_is_fun: usize = 0;
#[no_mangle]
pub static enif_is_identical: usize = 0;
#[no_mangle]
pub static enif_is_list: usize = 0;
#[no_mangle]
pub static enif_is_map: usize = 0;
#[no_mangle]
pub static enif_is_number: usize = 0;
#[no_mangle]
pub static enif_is_pid: usize = 0;
#[no_mangle]
pub static enif_is_port: usize = 0;
#[no_mangle]
pub static enif_is_process_alive: usize = 0;
#[no_mangle]
pub static enif_is_ref: usize = 0;
#[no_mangle]
pub static enif_is_tuple: usize = 0;
#[no_mangle]
pub static enif_make_atom_len: usize = 0;
#[no_mangle]
pub static enif_make_badarg: usize = 0;
#[no_mangle]
pub static enif_make_binary: usize = 0;
#[no_mangle]
pub static enif_make_copy: usize = 0;
#[no_mangle]
pub static enif_make_double: usize = 0;
#[no_mangle]
pub static enif_make_existing_atom_len: usize = 0;
#[no_mangle]
pub static enif_make_int: usize = 0;
#[no_mangle]
pub static enif_make_list_cell: usize = 0;
#[no_mangle]
pub static enif_make_list_from_array: usize = 0;
#[no_mangle]
pub static enif_make_long: usize = 0;
#[no_mangle]
pub static enif_make_map_from_arrays: usize = 0;
#[no_mangle]
pub static enif_make_map_put: usize = 0;
#[no_mangle]
pub static enif_make_map_remove: usize = 0;
#[no_mangle]
pub static enif_make_map_update: usize = 0;
#[no_mangle]
pub static enif_make_new_binary: usize = 0;
#[no_mangle]
pub static enif_make_new_map: usize = 0;
#[no_mangle]
pub static enif_make_reverse_list: usize = 0;
#[no_mangle]
pub static enif_make_sub_binary: usize = 0;
#[no_mangle]
pub static enif_make_tuple_from_array: usize = 0;
#[no_mangle]
pub static enif_make_uint: usize = 0;
#[no_mangle]
pub static enif_make_ulong: usize = 0;
#[no_mangle]
pub static enif_map_iterator_create: usize = 0;
#[no_mangle]
pub static enif_map_iterator_destroy: usize = 0;
#[no_mangle]
pub static enif_map_iterator_get_pair: usize = 0;
#[no_mangle]
pub static enif_map_iterator_next: usize = 0;
#[no_mangle]
pub static enif_map_iterator_prev: usize = 0;
#[no_mangle]
pub static enif_open_resource_type: usize = 0;
#[no_mangle]
pub static enif_raise_exception: usize = 0;
#[no_mangle]
pub static enif_realloc_binary: usize = 0;
#[no_mangle]
pub static enif_release_binary: usize = 0;
#[no_mangle]
pub static enif_schedule_nif: usize = 0;
#[no_mangle]
pub static enif_self: usize = 0;
#[no_mangle]
pub static enif_snprintf: usize = 0;
#[no_mangle]
pub static enif_term_to_binary: usize = 0;
#[no_mangle]
pub static enif_term_type: usize = 0;
42 changes: 42 additions & 0 deletions rustler_tool/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#[cfg(unix)]
mod fake_symbols;
mod nif;

use std::path::PathBuf;

use clap::{Parser, Subcommand};

use crate::nif::NifLibrary;

#[derive(Parser)]
#[command(version, about, long_about = None)]
struct Cli {
#[command(subcommand)]
command: Option<Commands>,
}

#[derive(Subcommand)]
enum Commands {
/// does testing things
Nif { path: PathBuf },
}

fn main() {
let cli = Cli::parse();

match &cli.command {
Some(Commands::Nif { path }) => {
println!("Extracting nifs from {:?}", path);

let lib = NifLibrary::load(&path).unwrap();

println!("Found library {} with nifs", lib.name);
for nif in lib.nifs {
println!(" {}/{}", nif.name, nif.arity);
}
}
None => {
panic!("No command given")
}
}
}
67 changes: 67 additions & 0 deletions rustler_tool/src/nif.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use libloading::{Library, Symbol};
use rustler_sys::ErlNifEntry;
use std::ffi::CStr;
use std::path::{Path, PathBuf};

pub struct Nif {
pub name: String,
pub arity: usize,
pub flags: usize,
}

pub struct NifLibrary {
pub path: PathBuf,
pub name: String,
pub nifs: Vec<Nif>,
}

#[cfg(unix)]
unsafe fn maybe_call_nif_init(
lib: &Library,
) -> Result<*const ErlNifEntry, Box<dyn std::error::Error>> {
let func: Symbol<unsafe extern "C" fn() -> *const ErlNifEntry> = lib.get(b"nif_init")?;

Ok(func())
}

#[cfg(windows)]
unsafe fn maybe_call_nif_init(
lib: &Library,
) -> Result<*const ErlNifEntry, Box<dyn std::error::Error>> {
use rustler_sys::TWinDynNifCallbacks;
static NULL_CALLBACKS: TWinDynNifCallbacks = TWinDynNifCallbacks {};
let func: Symbol<unsafe extern "C" fn(*mut TWinDynNifCallbacks) -> *const ErlNifEntry> =
lib.get(b"nif_init")?;

func(&NULL_CALLBACKS)
}

impl NifLibrary {
pub fn load(path: &Path) -> Result<NifLibrary, Box<dyn std::error::Error>> {
unsafe {
let lib = Library::new(&path)?;
let entry = maybe_call_nif_init(&lib)?;

let name = CStr::from_ptr((*entry).name).to_str()?.to_string();
let nif_array =
std::slice::from_raw_parts((*entry).funcs, (*entry).num_of_funcs as usize);

let nifs = nif_array
.into_iter()
.filter_map(|f| {
Some(Nif {
name: CStr::from_ptr((*f).name).to_str().ok()?.to_string(),
arity: (*f).arity as usize,
flags: (*f).flags as usize,
})
})
.collect();

Ok(NifLibrary {
path: path.to_path_buf(),
name,
nifs,
})
}
}
}

0 comments on commit 2366e44

Please sign in to comment.