commonlibsse_ng_proc_macro_common\relocate_fn/
mod.rs1mod attr_args;
2
3use crate::fn_args_parser::{FnArgs, create_fn_args};
4use proc_macro2::TokenStream;
5
6pub fn gen_relocate_fn(
7 attrs: TokenStream,
8 item_fn: syn::ItemFn,
9 crate_root_name: TokenStream,
10) -> TokenStream {
11 let args = {
12 let attr_args = match darling::ast::NestedMeta::parse_meta_list(attrs) {
13 Ok(v) => v,
14 Err(e) => {
15 return darling::Error::from(e).write_errors();
16 }
17 };
18
19 match <attr_args::MacroArgs as darling::FromMeta>::from_list(&attr_args) {
20 Ok(v) => v,
21 Err(e) => {
22 return e.write_errors();
23 }
24 }
25 };
26 generate_code(args, item_fn, crate_root_name)
27}
28
29fn generate_code(
30 args: attr_args::MacroArgs,
31 item_fn: syn::ItemFn,
32 crate_root_name: TokenStream,
33) -> TokenStream {
34 let attr_args::MacroArgs { se_id, ae_id, vr_id } = args;
35 let vr_id = vr_id.unwrap_or(se_id);
36
37 let syn::ItemFn { attrs, vis, sig, block } = &item_fn;
38 let syn::Signature {
39 constness,
40 asyncness,
41 unsafety,
42 abi,
43 ident,
44 generics,
45 inputs: fn_inputs,
46 variadic,
47 output: fn_output,
48 ..
49 } = &sig;
50
51 let FnArgs { call_args, type_args, self_type, cast_self } = create_fn_args(fn_inputs, variadic);
52
53 let fn_type = quote::quote! { #constness #asyncness #unsafety #abi fn #generics (#self_type #type_args) #fn_output };
54
55 let fn_sig = quote::quote! { #vis #constness #asyncness #unsafety #abi fn #ident #generics (#fn_inputs) #fn_output };
56 let stmts = &block.stmts;
57
58 #[cfg(feature = "tracing")]
59 let database_err_log = quote::quote! { #crate_root_name::__private::tracing::error!("[Critical Error] Failed to resolve address: {err}") };
60 #[cfg(not(feature = "tracing"))]
61 let database_err_log = quote::quote! {};
62
63 #[cfg(feature = "tracing")]
64 let ptr_err_log = quote::quote! {
65 #crate_root_name::__private::tracing::error!(
66 "Resolved Address, but no permission permission to access this address: {:#?} (se_id: {}, ae_id: {}, vr_id: {})",
67 fn_ptr.as_ptr(),
68 #se_id,
69 #ae_id,
70 #vr_id
71 );
72 };
73 #[cfg(not(feature = "tracing"))]
74 let ptr_err_log = quote::quote! {};
75
76 quote::quote! {
77 #(#attrs)*
78 #[allow(clippy::use_self)]
79 #fn_sig {
80 #(#stmts)*
81
82 type SelfSignature = #fn_type;
87
88 {
89 static FUNC: std::sync::LazyLock<SelfSignature> = std::sync::LazyLock::new(|| {
90 use core::ptr::NonNull;
91
92 use #crate_root_name::rel::id::RelocationID;
93 use #crate_root_name::rel::ResolvableAddress as _;
94
95 let fn_ptr = RelocationID::new(#se_id, #ae_id, #vr_id).address().unwrap_or_else(|err| {
96 #database_err_log;
97 panic!("Failed to resolve address: {err}");
98 });
99 if !#crate_root_name::rex::win32::is_valid_range(fn_ptr.as_ptr().cast(), core::mem::size_of::<usize>()) {
100 #ptr_err_log;
101 }
102 unsafe { core::mem::transmute::<NonNull<core::ffi::c_void>, SelfSignature>(fn_ptr) }
103 });
104 FUNC(#cast_self #call_args)
105 }
106 }
107 }
108}