I'm a bit lost at making dlsym()
work in Rust:
libc::dlsym()
returns a*mut c_void
handle to the desired function.- To use that handle, I need to cast it to
extern fn
, but that doesn't seem possible, even thoughfn
(extern
or not) appears to be a*mut
internally. - If I store the handle as
*mut extern fn
, as I did in the sample program below, I'm effectively storing a*mut
as a*mut *mut
(seegdb
output at the end), which, not surprisingly, will produce segfaults.
Sample program, which will segfault when handle
is invoked at line 15:
use std::ffi::CString;
fn main() {
let func_name = CString::new("fork").unwrap();
let handle: *mut extern "C" fn() -> libc::pid_t =
unsafe { libc::dlsym(libc::RTLD_NEXT, func_name.as_ptr()).cast() };
if handle.is_null() {
let error_msg = CString::new("dlsym(fork) failed: %s\n").unwrap();
unsafe { libc::printf(error_msg.as_ptr(), libc::dlerror()) };
panic!();
}
let pid = unsafe { (*handle)() };
if pid == 0 {
println!("parent pid = {}", unsafe { libc::getppid() });
} else if pid == -1 {
let error_msg = CString::new("fork() failed").unwrap();
unsafe { libc::perror(error_msg.as_ptr()) };
} else {
println!("child pid = {}", pid);
}
}
gdb
output:
(gdb) p handle
$1 = (*mut *mut fn () -> i32) 0x7f40b093b900 <__libc_fork>