diff --git a/.gitignore b/.gitignore index 6a73438..771fc85 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target /plugins /.cache +compile_commands.json diff --git a/Cargo.lock b/Cargo.lock index b5c21c8..0cc8d2a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -51,6 +51,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + [[package]] name = "bytes" version = "1.6.0" @@ -122,9 +128,10 @@ dependencies = [ ] [[package]] -name = "dim_plugin_helper" +name = "dim_sdk" version = "0.1.0" dependencies = [ + "anyhow", "bytes", "lazy_static", "libc", @@ -157,7 +164,7 @@ dependencies = [ name = "example_rust" version = "0.1.0" dependencies = [ - "dim_plugin_helper", + "dim_sdk", "lazy_static", ] diff --git a/Cargo.toml b/Cargo.toml index 13963cc..959038a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,4 @@ -workspace = { members = [ "dim_plugin_helper","dim_plugins/example_rust"] } +workspace = { members = [ "sdk/rust","dim_plugins/example_rust"] } [package] name = "dim" version = "0.1.0" diff --git a/Makefile b/Makefile index ef20583..ca57e79 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ CWD := $(dir $(realpath $(lastword $(MAKEFILE_LIST)))) PLUGIN_DIR = ${CWD}plugins OBJECT_DIR = $(CWD)target/objects BUILD_DIR = $(CWD)target -DIM_CC_FLAGS = -I$(CWD)include -rdynamic -shared -fPIC +DIM_CC_FLAGS = -I$(CWD)sdk/c_cxx DIM_CC = gcc BIN=$(BUILD_DIR)/dim @@ -21,7 +21,7 @@ target/release/dim: cargo build --release dim_plugins/%/Makefile: - $(MAKE) -C $(dir $@) \ + @$(MAKE) -C $(dir $@) \ -E "PLUGIN_DIR=$(PLUGIN_DIR)" \ -E "OBJECT_DIR=$(OBJECT_DIR)" \ -E "BUILD_DIR=$(BUILD_DIR)" \ diff --git a/compile_commands.json b/compile_commands.json index 2828583..b9aea03 100644 --- a/compile_commands.json +++ b/compile_commands.json @@ -7,8 +7,9 @@ "-o", "/home/mcorange/@Projects/xor64/dim/target/objects/example_c/main.o", "src/main.c", - "-fPIC", - "-pie" + "-pie", + "-I/home/mcorange/@Projects/xor64/dim/sdk/c_cxx", + "-fPIC" ], "file": "src/main.c" } diff --git a/dim_plugin_helper/src/lib.rs b/dim_plugin_helper/src/lib.rs deleted file mode 100644 index f4be733..0000000 --- a/dim_plugin_helper/src/lib.rs +++ /dev/null @@ -1,111 +0,0 @@ -use std::{ffi::{c_char, c_void, CStr, CString}, io::Write}; - -pub use libc::snprintf; - -#[repr(C)] -#[derive(Debug)] -pub struct PluginInfo { - ptrs: PluginInfoPtrs, - c_name: CString, - c_version: CString, - c_license: CString -} - -#[repr(C)] -#[derive(Debug)] -struct PluginInfoPtrs { - name: *const c_char, - version: *const c_char, - license: *const c_char, -} - -impl PluginInfo { - // pub fn new() -> Self { - // Self { - // name: std::ptr::null(), - // version: std::ptr::null(), - // license: std::ptr::null(), - // c_name: Default::default(), - // c_version: Default::default(), - // c_license: Default::default() - // } - //} - pub fn new(name: &str, version: &str, license: &str) -> Self { - - let c_name = CString::new(name).unwrap(); - let c_version = CString::new(version).unwrap(); - let c_license = CString::new(license).unwrap(); - let name = c_name.as_ptr(); - let version = if c_version.is_empty() { - std::ptr::null() - } else {c_version.as_ptr()}; - let license = if c_license.is_empty() { - std::ptr::null() - } else {c_license.as_ptr()}; - - Self { ptrs: PluginInfoPtrs{ name, version, license }, c_name, c_version, c_license } - } - - pub fn get(&self) -> *const c_void { - &self.ptrs as *const _ as *const c_void - } -} -unsafe impl Sync for PluginInfo {} - - -// Lord have mercy on me -#[macro_export] -macro_rules! plugin_info { - ($name:literal, $version:literal, $license:literal) => { - - lazy_static::lazy_static!( - static ref PLUGIN_INFO: PluginInfo = PluginInfo::new($name, $version, $license); - ); - - }; -} - - -#[derive(Debug)] -pub struct CBuffer { - inner: *mut i8, - count: usize, - capacity: usize -} - -impl CBuffer { - pub fn from_raw_parts_mut(buf: *mut i8, capacity: usize) -> Self { - Self { - inner: buf, - capacity, - count: 0, - } - - } -} - - -impl Write for CBuffer { - fn write(&mut self, buf: &[u8]) -> std::io::Result { - let mut count = 0; - - for c in buf { - unsafe { - if self.count + count >= self.capacity - 1 { - return Err(std::io::ErrorKind::OutOfMemory.into()); - } - (*self.inner.add(self.count + count)) = *c as i8; - } - count += 1; - } - unsafe { - (*self.inner.add(self.count + count)) = 0; - } - self.count += count; - - Ok(count as usize) - } - fn flush(&mut self) -> std::io::Result<()> { - Ok(()) - } -} diff --git a/dim_plugins/example_c/Makefile b/dim_plugins/example_c/Makefile index 951c7ff..a6a33d9 100644 --- a/dim_plugins/example_c/Makefile +++ b/dim_plugins/example_c/Makefile @@ -1,7 +1,7 @@ PLUGIN_NAME=example_c -CC_FLAGS = $(DIM_CC_FLAGS) +CC_FLAGS = $(DIM_CC_FLAGS) -fPIC SOURCES=$(wildcard src/*.c) OBJECTS=$(patsubst src/%.c,$(OBJECT_DIR)/$(PLUGIN_NAME)/%.o,$(SOURCES)) @@ -12,8 +12,8 @@ build: $(PLUGIN_DIR)/$(PLUGIN_NAME).dim $(PLUGIN_DIR)/$(PLUGIN_NAME).dim: $(OBJECTS) @mkdir -p $(dir $@) - $(DIM_CC) -o $@ $^ $(CC_FLAGS) + $(DIM_CC) -o $@ $^ -rdynamic -shared $(CC_FLAGS) $(OBJECT_DIR)/$(PLUGIN_NAME)/%.o: src/%.c @mkdir -p $(dir $@) - $(DIM_CC) -c -o $@ $< -fPIC -pie + $(DIM_CC) -c -o $@ $< -pie $(CC_FLAGS) diff --git a/dim_plugins/example_c/src/main.c b/dim_plugins/example_c/src/main.c index 8dd53e8..b54b3a8 100644 --- a/dim_plugins/example_c/src/main.c +++ b/dim_plugins/example_c/src/main.c @@ -2,9 +2,9 @@ #include #include -#include "../../../include/plug.h" +#include "dim_sdk.h" -PLUG_INFO("Example plugin", "0.0.0", "GPLv3") +PLUG_INFO("Example plugin", "0.0.1", "GPLv3") typedef struct plug_t { char* some_data; @@ -16,7 +16,6 @@ plug_t* p = {0}; void plug_init() { p = malloc(sizeof(plug_t)); assert(p != NULL && "Buy more ram KEKW"); - p->some_data = "hi :3"; p->count = 0; printf("Hello from plugin"); @@ -31,7 +30,7 @@ void plug_post_reload(void *state) { } void plug_poll(char *buf, size_t len) { - snprintf(buf, len, "%s (%d)", p->some_data, p->count++); + snprintf(buf, len, "Hello from C! (%d)", p->count++); } void plug_free() { diff --git a/dim_plugins/example_rust/Cargo.toml b/dim_plugins/example_rust/Cargo.toml index ab6f2ce..eb9e80f 100644 --- a/dim_plugins/example_rust/Cargo.toml +++ b/dim_plugins/example_rust/Cargo.toml @@ -8,5 +8,5 @@ crate-type=["cdylib"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -dim_plugin_helper = {path="../../dim_plugin_helper"} +dim_sdk = {path="../../sdk/rust/"} lazy_static = "1.4.0" diff --git a/dim_plugins/example_rust/Makefile b/dim_plugins/example_rust/Makefile index 9bb81c9..5c0a585 100644 --- a/dim_plugins/example_rust/Makefile +++ b/dim_plugins/example_rust/Makefile @@ -4,12 +4,12 @@ PLUGIN_NAME=example_rust build: $(PLUGIN_DIR)/$(PLUGIN_NAME).dim -$(PLUGIN_DIR)/$(PLUGIN_NAME).dim: $(OBJECT_DIR)/$(PLUGIN_NAME)/release/lib$(PLUGIN_NAME).so - cp $(OBJECT_DIR)/$(PLUGIN_NAME)/release/lib$(PLUGIN_NAME).so $(PLUGIN_DIR)/$(PLUGIN_NAME).dim +$(PLUGIN_DIR)/$(PLUGIN_NAME).dim: $(OBJECT_DIR)/$(PLUGIN_NAME)/debug/lib$(PLUGIN_NAME).so + cp $(OBJECT_DIR)/$(PLUGIN_NAME)/debug/lib$(PLUGIN_NAME).so $(PLUGIN_DIR)/$(PLUGIN_NAME).dim -$(OBJECT_DIR)/$(PLUGIN_NAME)/release/lib$(PLUGIN_NAME).so: +$(OBJECT_DIR)/$(PLUGIN_NAME)/debug/lib$(PLUGIN_NAME).so: mkdir -p $(OBJECT_DIR)/$(PLUGIN_NAME) - cargo build --release --target-dir $(OBJECT_DIR)/$(PLUGIN_NAME) + cargo build --target-dir $(OBJECT_DIR)/$(PLUGIN_NAME) diff --git a/dim_plugins/example_rust/src/lib.rs b/dim_plugins/example_rust/src/lib.rs index 5ce5413..24769cf 100644 --- a/dim_plugins/example_rust/src/lib.rs +++ b/dim_plugins/example_rust/src/lib.rs @@ -1,67 +1,48 @@ -use std::ffi::c_void; -use std::ffi::CStr; -use std::ffi::CString; -use std::io::BufWriter; -use std::io::Write; -use dim_plugin_helper::{plugin_info, PluginInfo}; +use std::fmt::Write; +use dim_sdk::{plugin_info, DimPlugin}; -plugin_info!("Example rust project", "owo", "nyaaa"); +plugin_info!( + Plug, // Your main global structs name that implements `DimPlugin` + "Example rust project", // Plugin name + "0.0.0", // Plugin Version (leave empty for none) + "GPLv3" // Plugin license (leave empty for none) + ); struct Plug { - pub some_data: String, + counter: usize, } impl Plug { pub fn new() -> Self { Self { - some_data: String::from("OwO") + counter: 0 } } } - -static mut PLUG: *mut Plug = std::ptr::null_mut(); - - -#[no_mangle] -extern "C" fn plug_get_info() -> *const c_void { - PLUGIN_INFO.get() -} - -#[no_mangle] -extern "C" fn plug_init() { - unsafe { - PLUG = (&mut Plug::new()) as *mut Plug; +impl DimPlugin for Plug { + fn init(&mut self) { + // Initialise data, this will run once, it will not run again after reload + } + fn poll(&mut self, f: &mut dim_sdk::CBuffer) -> dim_sdk::Result<()> { + // Write to buffer the text you want to display, keep this short + write!(f, "Hello from rust! ({})", self.counter)?; + self.counter += 1; + Ok(()) + } + fn pre_reload(&mut self) { + // Do stuff before reload, probably save important things because theres a good chance + // (especially on rust) that if you change the data layout it will die + } + fn post_reload(&mut self) { + // Do stuff after reloading plugin, state a.k.a this struct has the same data, will crash + // if the data layout changed + } + fn free(&mut self) { + // Yout probably dont need this but its for freeing things before the plugin gets unloaded } } -#[no_mangle] -extern "C" fn plug_pre_reload() -> *const () { - unsafe { - return PLUG as *const (); - } -} - -#[no_mangle] -extern "C" fn plug_post_reload(state: *mut ()) { - unsafe { - PLUG = state as *mut Plug; - } -} - -#[no_mangle] -extern "C" fn plug_poll(buf: *mut i8, len: usize) { - let mut buf = dim_plugin_helper::CBuffer::from_raw_parts_mut(buf, len); - // let mut buf = StringBuffer::from_raw_parts_mut(buf, len); - - let data = unsafe {(*PLUG).some_data.clone()}; - - let _ = write!(buf, "{}", data); -} - -#[no_mangle] -extern "C" fn plug_free() { - -} + diff --git a/examples/example.c b/examples/example.c deleted file mode 100644 index 3367629..0000000 --- a/examples/example.c +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include -#include - -#include "../include/plug.h" - -PLUG_NAME("Example plugin") -PLUG_VERSION("0.0.0") -PLUG_LICENSE("GPLv3") - -typedef struct plug_t { - char* some_data; -} plug_t; - -static plug_t* p = {0}; - -void plug_init() { - p = malloc(sizeof(plug_t)); - assert(p != NULL && "Buy more ram KEKW"); - p->some_data = "hi :3"; -} - -void* plug_pre_reload() { - return p; -} - -void plug_post_reload(void *state) { - p = state; -} - -void plug_poll(char *buf, size_t len) { - snprintf(buf, len, "%s", p->some_data); -} - -void plug_free() { - free(p); -} diff --git a/include/plug.h b/sdk/c_cxx/dim_sdk.h similarity index 100% rename from include/plug.h rename to sdk/c_cxx/dim_sdk.h diff --git a/dim_plugin_helper/Cargo.toml b/sdk/rust/Cargo.toml similarity index 75% rename from dim_plugin_helper/Cargo.toml rename to sdk/rust/Cargo.toml index 5171619..40c7f88 100644 --- a/dim_plugin_helper/Cargo.toml +++ b/sdk/rust/Cargo.toml @@ -1,12 +1,13 @@ [package] -name = "dim_plugin_helper" +name = "dim_sdk" version = "0.1.0" edition = "2021" [lib] -name="dim_plugin_helper" +name="dim_sdk" [dependencies] +anyhow = "1.0.86" bytes = "1.6.0" lazy_static = { version = "1.4.0", features = ["spin"] } libc = "0.2.155" diff --git a/sdk/rust/src/c_buffer.rs b/sdk/rust/src/c_buffer.rs new file mode 100644 index 0000000..4ae6f51 --- /dev/null +++ b/sdk/rust/src/c_buffer.rs @@ -0,0 +1,36 @@ +#[derive(Debug)] +pub struct CBuffer<'a> { + inner: &'a mut [i8], + count: usize, + capacity: usize +} + +#[allow(dead_code)] // rust_analyzer too dumb to see my macro magic + // i hate that macro as much as you do +impl CBuffer<'_> { + pub fn from_raw_parts_mut(buf: *mut i8, capacity: usize) -> Self { + Self { + inner: unsafe { + std::slice::from_raw_parts_mut(buf, capacity) + }, + capacity, + count: 0, + } + + } +} + + +impl std::fmt::Write for CBuffer<'_> { + fn write_str(&mut self, buf: &str) -> Result<(), std::fmt::Error> { + for c in buf.as_bytes() { + if self.count >= self.capacity - 1 { + return Ok(()); + } + self.inner[self.count] = *c as i8; + self.count += 1; + } + self.inner[self.count] = 0; + Ok(()) + } +} diff --git a/sdk/rust/src/lib.rs b/sdk/rust/src/lib.rs new file mode 100644 index 0000000..2a6688f --- /dev/null +++ b/sdk/rust/src/lib.rs @@ -0,0 +1,25 @@ + + +#[macro_use] +mod magic; +mod c_buffer; +mod plugin_info; + +pub use c_buffer::*; +pub use plugin_info::*; + +pub use anyhow::Result; + +pub trait DimPlugin { + fn init(&mut self); + fn pre_reload(&mut self); + fn post_reload(&mut self); + fn poll(&mut self, f: &mut CBuffer) -> Result<()>; + fn free(&mut self) {} +} + + + + + + diff --git a/sdk/rust/src/magic.rs b/sdk/rust/src/magic.rs new file mode 100644 index 0000000..b1153df --- /dev/null +++ b/sdk/rust/src/magic.rs @@ -0,0 +1,53 @@ +// Lord have mercy on me +#[macro_export] +macro_rules! plugin_info { + ($typ:ty, $name:literal, $version:literal, $license:literal) => { + + lazy_static::lazy_static!( + static ref PLUGIN_INFO: $crate::PluginInfo = $crate::PluginInfo::new($name, $version, $license); + ); + + static mut PLUG: *mut $typ = std::ptr::null_mut() as *mut $typ; + + #[no_mangle] + unsafe extern "C" fn plug_get_info() -> *const std::ffi::c_void { + PLUGIN_INFO.get_raw_ptr() + } + + #[no_mangle] + unsafe extern "C" fn plug_init() { + PLUG = std::alloc::alloc(std::alloc::Layout::new::<$typ>()) as *mut $typ; + *PLUG = Plug::new(); + (&mut *PLUG).init(); + } + + #[no_mangle] + unsafe extern "C" fn plug_pre_reload() -> *mut $typ { + //TODO: Untested + (&mut *PLUG).pre_reload(); + return PLUG; + } + + #[no_mangle] + unsafe extern "C" fn plug_post_reload(state: *mut $typ) { + //TODO: Untested + PLUG = state; + (&mut *PLUG).post_reload(); + } + + #[no_mangle] + unsafe extern "C" fn plug_poll(buf: *mut i8, len: std::ffi::c_uint) { + let mut buf = $crate::CBuffer::from_raw_parts_mut(buf, len as usize); + if let Err(_e) = (&mut *PLUG).poll(&mut buf) { + // TODO: Handle error maybe? + } + } + + #[no_mangle] + unsafe extern "C" fn plug_free() { + std::alloc::dealloc(PLUG as *mut u8, std::alloc::Layout::new::<$typ>()); + (&mut *PLUG).free(); + } + + }; +} diff --git a/sdk/rust/src/plugin_info.rs b/sdk/rust/src/plugin_info.rs new file mode 100644 index 0000000..835de11 --- /dev/null +++ b/sdk/rust/src/plugin_info.rs @@ -0,0 +1,41 @@ +use std::ffi::{c_char, c_void, CString}; + +#[derive(Debug)] +pub struct PluginInfo { + ptrs: PluginInfoPtrs, + _name: CString, + _version: CString, + _license: CString +} + +#[repr(C)] +#[derive(Debug)] +struct PluginInfoPtrs { + name: *const c_char, + version: *const c_char, + license: *const c_char, +} + +impl PluginInfo { + pub fn new(name: &str, version: &str, license: &str) -> Self { + + let _name = CString::new(name).unwrap(); + let _version = CString::new(version).unwrap(); + let _license = CString::new(license).unwrap(); + let name = _name.as_ptr(); + let version = if _version.is_empty() { + std::ptr::null() + } else {_version.as_ptr()}; + let license = if _license.is_empty() { + std::ptr::null() + } else {_license.as_ptr()}; + + Self { ptrs: PluginInfoPtrs{ name, version, license }, _name, _version, _license } + } + + pub fn get_raw_ptr(&self) -> *const c_void { + &self.ptrs as *const _ as *const c_void + } +} +unsafe impl Sync for PluginInfo {} + diff --git a/src/plugman/mod.rs b/src/plugman/mod.rs index 3040d38..dafdaf4 100644 --- a/src/plugman/mod.rs +++ b/src/plugman/mod.rs @@ -37,6 +37,8 @@ impl PlugMan { self.load(entry.path().to_path_buf())?; } } + println!("INFO: Loaded {} plugins", self.plugins.len()); + Ok(()) } @@ -81,18 +83,18 @@ impl PlugMan { #[derive(Debug)] pub enum PluginError { - DlOpenError(dlopen::Error), - IoError(std::io::Error) + DlOpenError, + IoError } impl From for PluginError { - fn from(value: dlopen::Error) -> Self { - Self::DlOpenError(value) + fn from(_: dlopen::Error) -> Self { + Self::DlOpenError } } impl From for PluginError { - fn from(value: std::io::Error) -> Self { - Self::IoError(value) + fn from(_: std::io::Error) -> Self { + Self::IoError } } diff --git a/src/plugman/plugin.rs b/src/plugman/plugin.rs index 73aec7b..208c792 100644 --- a/src/plugman/plugin.rs +++ b/src/plugman/plugin.rs @@ -1,4 +1,4 @@ -use std::{alloc::Layout, ffi::{c_char, CStr, CString}, path::PathBuf}; +use std::{alloc::Layout, ffi::{c_char, c_uint, CStr, CString}, path::PathBuf}; use dlopen::raw::Library; @@ -90,6 +90,10 @@ impl Plugin { let s = unsafe { (self.syms().poll)(buf as *mut i8, cap); let len = libc::strlen(buf as *const i8); + if len > cap { + panic!("String len is bigger than allocatd"); + } + String::from_raw_parts(buf, len, cap) };