4 Commits
Author SHA1 Message Date
pancake c72b4cba60 fi 2026-02-20 13:49:51 +01:00
pancake 391641f2ff Use libload instead of dlopen for portability reasons 2026-02-20 13:40:45 +01:00
Jonathan Creekmore 1208b28183 Provide a proper Default impl for R2PipeSpawnOptions 2023-06-08 18:28:46 -04:00
RHL120 522a9f7a4f Fix docs link in README 2022-12-30 13:05:38 -05:00
6 changed files with 53 additions and 83 deletions

No files matched your search

+5 -1
View File
@@ -20,8 +20,12 @@ readme = "README.md"
# License information
license = "MIT OR Apache-2.0"
[features]
docsrs = []
[dependencies]
libc = "0.2.81"
libloading = "0.8"
libc = "0.2"
serde = "1.0.118"
serde_json = "1.0.60"
serde_derive = "1.0.118"
+1 -1
View File
@@ -10,7 +10,7 @@ r2pipe.rs
The Rust Crate to interact with radare2.
Please check [Documentation](https://radare.github.io/r2pipe.rs) to get
Please check [Documentation](https://docs.rs/r2pipe/latest/r2pipe/) to get
started.
**NOTICE**
+19 -50
View File
@@ -1,60 +1,29 @@
use crate::{Error, Result};
use libc::*;
use crate::Result;
use libloading::{Library, Symbol};
use std::sync::Mutex;
// Contains a handle to the library.
pub struct LibHandle(std::sync::Mutex<*mut c_void>);
pub fn to_cstr(s: &str) -> Result<*const c_char> {
Ok(std::ffi::CString::new(s)
.map_err(|_| Error::SharedLibraryLoadError)?
.into_raw())
}
pub fn free_cstr(ptr: *const c_char) {
let _ = unsafe { std::ffi::CString::from_raw(ptr as *mut _) };
}
/// Contains a handle to the dynamically loaded library.
pub struct LibHandle(Mutex<Library>);
impl LibHandle {
/// Load a shared library by name with platform-specific extension.
pub fn new(name: &str, end: Option<&str>) -> Result<LibHandle> {
let name = to_cstr(&format!(
"{}{}{}",
name,
if cfg!(windows) {
".dll"
} else if cfg!(macos) {
".dylib"
} else {
".so"
},
end.unwrap_or("")
))?;
let ret = unsafe { dlopen(name, RTLD_LAZY) };
free_cstr(name);
if ret.is_null() {
Err(Error::SharedLibraryLoadError)
let ext = if cfg!(windows) {
".dll"
} else if cfg!(target_os = "macos") {
".dylib"
} else {
Ok(LibHandle(std::sync::Mutex::new(ret)))
}
".so"
};
let lib_name = format!("{}{}{}", name, ext, end.unwrap_or(""));
let lib = unsafe { Library::new(&lib_name) }?;
Ok(LibHandle(Mutex::new(lib)))
}
/// Load a symbol from the library and transmute it to the desired type.
pub unsafe fn load_sym<T>(&mut self, name: &str) -> Result<T> {
let handle = *self.0.lock().unwrap();
let name = to_cstr(name)?;
let sym = dlsym(handle, name);
free_cstr(name);
if sym.is_null() {
Err(Error::SharedLibraryLoadError)
} else {
Ok(std::mem::transmute_copy(&sym))
}
}
}
impl Drop for LibHandle {
fn drop(&mut self) {
let handle = *self.0.lock().unwrap();
// In some cases, dlclose is not required to do anything. We allow it
// to silently fail.
let _ = unsafe { libc::dlclose(handle) };
let lib = self.0.lock().unwrap();
let sym: Symbol<T> = lib.get(name.as_bytes())?;
Ok(std::mem::transmute_copy::<_, T>(&*sym))
}
}
+2 -2
View File
@@ -42,6 +42,6 @@ pub enum Error {
ChannelSendError(#[from] SendError<String>),
/// Error loading radare2 shared library.
#[error("Shared library load error")]
SharedLibraryLoadError,
#[error("Shared library error: {0}")]
SharedLibraryError(#[from] libloading::Error),
}
+1 -1
View File
@@ -50,7 +50,7 @@
//! The crate offers various methods to interact with r2pipe, eg. via process (multi-threadable), http or tcp.
//! Check the examples/ dir for more complete examples.
#![cfg_attr(doc_cfg, feature(doc_cfg))]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![doc(html_root_url = "https://radare.github.io/r2pipe.rs/")]
#[macro_use]
+25 -28
View File
@@ -53,12 +53,23 @@ pub struct R2PipeThread {
pub handle: thread::JoinHandle<Result<()>>,
}
#[derive(Default, Clone)]
#[derive(Clone)]
pub struct R2PipeSpawnOptions {
pub exepath: String,
pub args: Vec<&'static str>,
}
impl Default for R2PipeSpawnOptions {
fn default() -> Self {
let exepath = if cfg!(windows) { "radare2.exe" } else { "r2" };
R2PipeSpawnOptions {
exepath: exepath.to_string(),
args: Vec::default(),
}
}
}
/// Provides abstraction between the three invocation methods.
pub struct R2Pipe(Box<dyn Pipe>);
pub trait Pipe {
@@ -177,26 +188,13 @@ impl R2Pipe {
}
/// Creates a new R2PipeSpawn.
pub fn spawn<T: AsRef<str>>(name: T, opts: Option<R2PipeSpawnOptions>) -> Result<R2Pipe> {
pub fn spawn<T: AsRef<str>>(name: T, mut opts: Option<R2PipeSpawnOptions>) -> Result<R2Pipe> {
if name.as_ref() == "" && R2Pipe::in_session().is_some() {
return R2Pipe::open();
}
let exepath = match opts {
Some(ref opt) => opt.exepath.clone(),
_ => {
if cfg!(windows) {
"radare2.exe"
} else {
"r2"
}
}
.to_owned(),
};
let args = match opts {
Some(ref opt) => opt.args.clone(),
_ => vec![],
};
let R2PipeSpawnOptions { exepath, args } = opts.take().unwrap_or_default();
let path = Path::new(name.as_ref());
let mut child = Command::new(exepath)
.arg("-q0")
@@ -386,24 +384,23 @@ impl R2PipeNative {
let r_core_cmd_str_handle = unsafe { lib.load_sym("r_core_cmd_str")? };
let r_core = r_core_new();
if r_core.is_null() {
Err(Error::SharedLibraryLoadError)
} else {
let mut ret = R2PipeNative {
lib,
r_core: std::sync::Mutex::new(r_core),
r_core_cmd_str_handle,
};
ret.cmd(&format!("o {}", file))?;
Ok(ret)
return Err(Error::EmptyResponse);
}
let mut ret = R2PipeNative {
lib,
r_core: std::sync::Mutex::new(r_core),
r_core_cmd_str_handle,
};
ret.cmd(&format!("o {}", file))?;
Ok(ret)
}
}
impl Pipe for R2PipeNative {
fn cmd(&mut self, cmd: &str) -> Result<String> {
let r_core = *self.r_core.lock().unwrap();
let cmd = dlfcn::to_cstr(cmd)?;
let res = (self.r_core_cmd_str_handle)(r_core, cmd);
let cmd = std::ffi::CString::new(cmd).map_err(|_| Error::ArgumentMismatch)?;
let res = (self.r_core_cmd_str_handle)(r_core, cmd.as_ptr());
if res.is_null() {
Err(Error::EmptyResponse)
} else {