From 2366e443961a227a8ebb6fc8dd2b2cd8a1489995 Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Wed, 29 May 2024 10:53:14 +0200 Subject: [PATCH] Initial commit for NIF inspection tool --- Cargo.toml | 2 +- rustler_tool/.cargo/config.toml | 2 + rustler_tool/Cargo.toml | 9 ++ rustler_tool/src/fake_symbols.rs | 148 +++++++++++++++++++++++++++++++ rustler_tool/src/main.rs | 42 +++++++++ rustler_tool/src/nif.rs | 67 ++++++++++++++ 6 files changed, 269 insertions(+), 1 deletion(-) create mode 100644 rustler_tool/.cargo/config.toml create mode 100644 rustler_tool/Cargo.toml create mode 100644 rustler_tool/src/fake_symbols.rs create mode 100644 rustler_tool/src/main.rs create mode 100644 rustler_tool/src/nif.rs diff --git a/Cargo.toml b/Cargo.toml index 6b494faa..a61dc1f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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", diff --git a/rustler_tool/.cargo/config.toml b/rustler_tool/.cargo/config.toml new file mode 100644 index 00000000..e2bab392 --- /dev/null +++ b/rustler_tool/.cargo/config.toml @@ -0,0 +1,2 @@ +[target.x86_64-unknown-linux-gnu] +rustflags = [ "-C", "link-args=-Wl,-export-dynamic" ] diff --git a/rustler_tool/Cargo.toml b/rustler_tool/Cargo.toml new file mode 100644 index 00000000..14f40e0e --- /dev/null +++ b/rustler_tool/Cargo.toml @@ -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" } diff --git a/rustler_tool/src/fake_symbols.rs b/rustler_tool/src/fake_symbols.rs new file mode 100644 index 00000000..d385e072 --- /dev/null +++ b/rustler_tool/src/fake_symbols.rs @@ -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; diff --git a/rustler_tool/src/main.rs b/rustler_tool/src/main.rs new file mode 100644 index 00000000..b977e80c --- /dev/null +++ b/rustler_tool/src/main.rs @@ -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, +} + +#[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") + } + } +} diff --git a/rustler_tool/src/nif.rs b/rustler_tool/src/nif.rs new file mode 100644 index 00000000..673e1204 --- /dev/null +++ b/rustler_tool/src/nif.rs @@ -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, +} + +#[cfg(unix)] +unsafe fn maybe_call_nif_init( + lib: &Library, +) -> Result<*const ErlNifEntry, Box> { + let func: Symbol *const ErlNifEntry> = lib.get(b"nif_init")?; + + Ok(func()) +} + +#[cfg(windows)] +unsafe fn maybe_call_nif_init( + lib: &Library, +) -> Result<*const ErlNifEntry, Box> { + use rustler_sys::TWinDynNifCallbacks; + static NULL_CALLBACKS: TWinDynNifCallbacks = TWinDynNifCallbacks {}; + let func: Symbol *const ErlNifEntry> = + lib.get(b"nif_init")?; + + func(&NULL_CALLBACKS) +} + +impl NifLibrary { + pub fn load(path: &Path) -> Result> { + 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, + }) + } + } +}